1 Introduction

This document provides an introduction of the R/Biocondcutor ELMER package, which is designed to combine DNA methylation and gene expression data from human tissues to infer multi-level cis-regulatory networks. ELMER uses DNA methylation to identify enhancers, and correlates enhancer state with expression of nearby genes to identify one or more transcriptional targets. Transcription factor (TF) binding site analysis of enhancers is coupled with expression analysis of all TFs to infer upstream regulators. This package can be easily applied to TCGA public available cancer data sets and custom DNA methylation and gene expression data sets.

ELMER analyses have 5 main steps:

  1. Identify distal probes on HM450K.
  2. Identify distal enhancer probes with significantly different DNA methylation level in control group and experiment group.
  3. Identify putative target genes for differentially methylated distal enhancer probes.
  4. Identify enriched motifs for the distal enhancer probes which are significantly differentially methylated and linked to putative target gene.
  5. Identify regulatory TFs whose expression associate with DNA methylation at motifs.

1.1 Package workflow

The package workflow is showed in the figure below:

ELMER workflow: ELMER receives as input a DNA methylation object, a gene expression object (both can be either a matrix or a SummarizedExperiment object) and a Genomic Ranges (GRanges) object with distal probes to be used as filter which can be retrieved using the get.feature.probe function. The function createMAE will create a Multi Assay Experiment object keeping only samples that have both DNA methylation and gene expression data. Genes will be mapped to genomic position and annotated using ENSEMBL database, while for probes it will add annotation from (http://zwdzwd.github.io/InfiniumAnnotation). This MAE object will be used as input to the next analysis functions. First, it identifies differentially methylated probes followed by the identification of their nearest genes (10 upstream and 10 downstream) through the get.diff.meth and GetNearGenes functions respectively. For each probe it will verify if any of the nearby genes were affected by its change in the DNA methylation level and a list of gene and probes pairs will be outputted from get.pair function. For the probes in those pairs, it will search for enriched regulatory Transcription Factors motifs with the get.enriched.motif function. Finally, the enriched motifs will be correlate with the level of the transcription factor through the get.TFs function. In the figure green Boxes represents user input data, blue boxes represents output object, orange boxes represents auxiliary pre-computed data and gray boxes are functions.

ELMER workflow: ELMER receives as input a DNA methylation object, a gene expression object (both can be either a matrix or a SummarizedExperiment object) and a Genomic Ranges (GRanges) object with distal probes to be used as filter which can be retrieved using the get.feature.probe function. The function createMAE will create a Multi Assay Experiment object keeping only samples that have both DNA methylation and gene expression data. Genes will be mapped to genomic position and annotated using ENSEMBL database, while for probes it will add annotation from (http://zwdzwd.github.io/InfiniumAnnotation). This MAE object will be used as input to the next analysis functions. First, it identifies differentially methylated probes followed by the identification of their nearest genes (10 upstream and 10 downstream) through the get.diff.meth and GetNearGenes functions respectively. For each probe it will verify if any of the nearby genes were affected by its change in the DNA methylation level and a list of gene and probes pairs will be outputted from get.pair function. For the probes in those pairs, it will search for enriched regulatory Transcription Factors motifs with the get.enriched.motif function. Finally, the enriched motifs will be correlate with the level of the transcription factor through the get.TFs function. In the figure green Boxes represents user input data, blue boxes represents output object, orange boxes represents auxiliary pre-computed data and gray boxes are functions.

1.2 Installing and loading ELMER

To install this package, start R and enter:

devtools::install_github(repo = "tiagochst/ELMER.data")
devtools::install_github(repo = "tiagochst/ELMER")

Then, to load ELMER enter:

1.3 Citing this work

If you used ELMER package or its results, please cite:

  • Yao, L., Shen, H., Laird, P. W., Farnham, P. J., & Berman, B. P. “Inferring regulatory element landscapes and transcription factor networks from cancer methylomes.” Genome Biol 16 (2015): 105.
  • Yao, Lijing, Benjamin P. Berman, and Peggy J. Farnham. “Demystifying the secret mission of enhancers: linking distal regulatory elements to target genes.” Critical reviews in biochemistry and molecular biology 50.6 (2015): 550-573.

If you get TCGA data using getTCGA function, please cite TCGAbiolinks package:

  • Colaprico A, Silva TC, Olsen C, Garofano L, Cava C, Garolini D, Sabedot T, Malta TM, Pagnotta SM, Castiglioni I, Ceccarelli M, Bontempi G and Noushmehr H. “TCGAbiolinks: an R/Bioconductor package for integrative analysis of TCGA data.” Nucleic acids research (2015): gkv1507.
  • “TCGA Workflow: Analyze cancer genomics and epigenomics data using Bioconductor packages”. F1000Research 10.12688/f1000research.8923.2 (T. Silva et al. 2016)

2 Download example data

The following steps can be used to download the example data set for ELMER.

3 Quick start: running TCGA example

TCGA.pipe is a function for easily downloading TCGA data and performing all the analyses in ELMER. For illustration purpose, we skip the downloading step. The user can use the getTCGA function to download TCGA data or use TCGA.pipe by including “download” in the analysis option.

The following command will do distal DNA methylation analysis and predict putative target genes, motif analysis and identify regulatory transcription factors.

TCGA.pipe("LUSC",
          wd = "./ELMER.example",
          cores = parallel::detectCores()/2,
          mode = "unsupervised"
          permu.size = 300,
          Pe = 0.01,
          analysis = c("distal.probes","diffMeth","pair","motif","TF.search"),
          diff.dir = "hypo",
          rm.chr = paste0("chr",c("X","Y")))
TCGA.pipe: Mode argument

In this new version we added the argument mode in the TCGA.pipe function. This will automatically set the minSubgroupFrac to the following values:

Modes available:

  • unsupervised:
  • Use 20% of each group to identify differently methylated regions (minSubgroupFrac = 0.2 in get.diff.meth)
  • Use 40% of all samples to create Unmethytlated (U) and Methylated (M) groups in the other steps (the lowest quintile of samples is the U group and the highest quintile samples is the M group) (minSubgroupFrac = 0.4 in get.pairs and get.TFs functions)
  • supervised:
  • Use all samples in all functions.

The unsupervised mode should be used when want to be able to detect a specific (possibly unknown) molecular subtype among tumor; these subtypes often make up only a minority of samples, and 20% was chosen as a lower bound for the purposes of statistical power. If you are using pre-defined group labels, such as treated replicates vs. untreated replicated, use supervised mode (use all samples)

For more informtaion continue reading the vignette.

4 Input data

A Multi Assay Experiment object is the input for all main functions of ELMER and can be generated by createMAE function.

To perform ELMER analyses, the Multi Assay Experiment needs:

  • a DNA methylation matrix or SummarizedExperiment object from HM450K or EPIC platform for multiple samples;
  • a gene expression matrix or SummarizedExperiment object for the same samples;
  • a matrix mapping DNA methylation samples to gene expression samples
  • a matrix with samples metadata (i.e. clinical data, molecular subtype information).

If TCGA data are used, the the last two matrices will be automatically generated. Based on the genome of reference selected, metadata for the DNA methylation probes, such as genomic coordinates, will be added from Wanding Zhou annotation(Zhou, Laird, and Shen 2016); and metadata for gene annotation will be added from ensemble database (Yates et al. 2015) using biomaRt (Durinck et al. 2009).

4.1 DNA methylation data

DNA methylation data feeding to ELMER should be a matrix of DNA methylation beta (\(\beta\)) value for samples (column) and probes (row) processed from row HM450K array data. If TCGA data is used, processed data from GDC website will be downloaded
and automatically transformed to the matrix by ELMER. The processed TCGA DNA methylation data were calculated as (M/(M+U)), where M represents the methylated allele intensity and U the unmethylated allele intensity. Beta values range from 0 to 1, reflecting the fraction of methylated alleles at each CpG in the each tumor; beta values close to 0 indicates low levels of DNA methylation and beta values close to 1 indicates high levels of DNA methylation.

If user have raw HM450K data, these data can be processed by Methylumi or minfi generating DNA methylation beta (\(\beta\)) value for each CpG site and multiple samples. The getBeta function in minfi can be used to generate a matrix of DNA methylation beta (\(\beta\)) value to feed in ELMER. And we recommend to save this matrix as meth.rda since createMAE can read in files by specifying their path which will help to reduce memory usage.

# Example of DNA methylation data input
datatable(Meth[1:10, 1:10], 
          options = list(scrollX = TRUE, keys = TRUE, pageLength = 5), 
          rownames = TRUE)

4.2 Gene expression data

Gene expresion data feeding to ELMER should be a matrix of gene expression values for samples (column) and genes (row). Gene expression value can be generated from different platforms: array or RNA-seq. The row data should be processed by other software to get gene or transcript level gene expression calls such as mapping by tophat, calling expression value by cufflink, RSEM or GenomeStudio for expression array. It is recommended to normalize expression data making gene expression comparable across samples such as quantile normalization. User can refer TCGA RNA-seq analysis pipeline to do generate comparable gene expression data. Then transform the gene expression values from each sample to the matrix for feeding into ELMER. If users want to use TCGA data, ELMER has functions to download the RNA-Seq Quantification data(HTSeq-FPKM-UQ) from GDC website and transform the data to the matrix for feeding into ELMER. It is recommended to save this matrix as RNA.rda since createMAE can read in files by specifying the path of files which will help to reduce memory usage.

# Example of Gene expression data input
datatable(GeneExp[1:10, 1:2], 
          options = list(scrollX = TRUE, keys = TRUE, pageLength = 5), 
          rownames = TRUE)

4.3 Sample information

Sample information should be stored as a data.frame object containing sample ID, group labels (control and experiment). Sample ID and groups labels are required. Other information for each sample can be added to this data.frame object. When TCGA data were used, samples information will be automatically generated by createMAE function by specifying option TCGA=TRUE. A columns name TN will create the groups Tumor and Normal using the following samples to each group:

Tumor samples are:

  • Primary solid Tumor
  • Recurrent Solid Tumor
  • Primary Blood Derived Cancer - Peripheral Blood
  • Recurrent Blood Derived Cancer - Bone Marrow
  • Additional - New Primary
  • Metastatic
  • Additional Metastatic
  • Human Tumor Original Cells
  • Primary Blood Derived Cancer - Bone Marrow

Normal samples:

  • Blood Derived Normal
  • Solid Tissue Normal
  • Buccal Cell Normal
  • EBV Immortalized Normal
  • Bone Marrow Normal
library(MultiAssayExperiment)
data <- createMAE(exp = GeneExp, 
                  met = Meth,
                  met.platform = "450K",
                  genome = "hg19",
                  save = FALSE,
                  TCGA = TRUE)
data
A MultiAssayExperiment object of 2 listed
 experiments with user-defined names and respective classes. 
 Containing an ExperimentList class object of length 2: 
 [1] DNA methylation: RangedSummarizedExperiment with 1707 rows and 234 columns 
 [2] Gene expression: RangedSummarizedExperiment with 3808 rows and 234 columns 
Features: 
 experiments() - obtain the ExperimentList instance 
 colData() - the primary/phenotype DataFrame 
 sampleMap() - the sample availability DataFrame 
 `$`, `[`, `[[` - extract colData columns, subset, or experiment 
 *Format() - convert ExperimentList into a long or wide DataFrame 
 assays() - convert ExperimentList to a SimpleList of matrices
as.data.frame(colData(data)[,c("patient","definition","TN")])
# Adding sample information for non TCGA samples
# You should have two objects with one for DNA methylation and 
# one for gene expression. They should have the same number of samples and the names of the 
# sample in the gene expression object and in hte DNA methylation matrix 
# should be the same
not.tcga.exp <- GeneExp # 234 samples
colnames(not.tcga.exp) <- substr(colnames(not.tcga.exp),1,15)
not.tcga.met <- Meth # 268 samples
colnames(not.tcga.met) <- substr(colnames(not.tcga.met),1,15)
# Number of samples in both objects (234)
table(colnames(not.tcga.met) %in% colnames(not.tcga.exp)) 

FALSE  TRUE 
   34   234 
# Our sample information must have as row names the samples information
phenotype.data <- data.frame(row.names = colnames(not.tcga.exp), 
                             samples = colnames(not.tcga.exp), 
                             group = c(rep("group1", ncol(GeneExp)/2),
                                       rep("group2", ncol(GeneExp)/2)))

data.hg19 <- createMAE(exp = not.tcga.exp, 
                       met =  not.tcga.met, 
                       TCGA = FALSE, 
                       met.platform = "450K",
                       genome = "hg19", 
                       colData = phenotype.data)
data.hg19
A MultiAssayExperiment object of 2 listed
 experiments with user-defined names and respective classes. 
 Containing an ExperimentList class object of length 2: 
 [1] DNA methylation: RangedSummarizedExperiment with 1707 rows and 234 columns 
 [2] Gene expression: RangedSummarizedExperiment with 3808 rows and 234 columns 
Features: 
 experiments() - obtain the ExperimentList instance 
 colData() - the primary/phenotype DataFrame 
 sampleMap() - the sample availability DataFrame 
 `$`, `[`, `[[` - extract colData columns, subset, or experiment 
 *Format() - convert ExperimentList into a long or wide DataFrame 
 assays() - convert ExperimentList to a SimpleList of matrices
# The samples that does not have data for both DNA methylation and Gene exprssion will be removed even for the phenotype data
phenotype.data <- data.frame(row.names = colnames(not.tcga.met), 
                             samples = colnames(not.tcga.met), 
                             group = c(rep("group1", ncol(Meth)/4),
                                       rep("group2", ncol(Meth)/4),
                                       rep("group3", ncol(Meth)/4),
                                       rep("group4", ncol(Meth)/4)))

data.hg38 <- createMAE(exp = not.tcga.exp, 
                       met =  not.tcga.met, 
                       TCGA = FALSE, 
                       save = FALSE,
                       met.platform = "450K",
                       genome = "hg38", 
                       colData = phenotype.data)
data.hg38
A MultiAssayExperiment object of 2 listed
 experiments with user-defined names and respective classes. 
 Containing an ExperimentList class object of length 2: 
 [1] DNA methylation: RangedSummarizedExperiment with 1702 rows and 234 columns 
 [2] Gene expression: RangedSummarizedExperiment with 3742 rows and 234 columns 
Features: 
 experiments() - obtain the ExperimentList instance 
 colData() - the primary/phenotype DataFrame 
 sampleMap() - the sample availability DataFrame 
 `$`, `[`, `[[` - extract colData columns, subset, or experiment 
 *Format() - convert ExperimentList into a long or wide DataFrame 
 assays() - convert ExperimentList to a SimpleList of matrices
as.data.frame(colData(data.hg38)[1:20,])

4.4 Probe information

Probe information is stored as a GRanges object containing the coordinates of each probe on the DNA methylation array and names of each probe. The default probe information is fetching from Wanding Zhou annotation(Zhou, Laird, and Shen 2016)

library(SummarizedExperiment, quietly = TRUE)
rowRanges(getMet(data))[1:3,1:8]
GRanges object with 3 ranges and 8 metadata columns:
             seqnames                 ranges strand |  addressA  addressB
                <Rle>              <IRanges>  <Rle> | <numeric> <numeric>
  cg00045114     chr1 [172674159, 172674160]      * |  52756415      <NA>
  cg00050294     chr1 [  2886818,   2886819]      * |  51670436      <NA>
  cg00066722     chr1 [ 43634520,  43634521]      * |  67752427      <NA>
                 channel designType    nextBase nextBaseRef   probeType
             <character>   <factor> <character> <character> <character>
  cg00045114        Both         II         G/A           C          cg
  cg00050294        Both         II         G/A           C          cg
  cg00066722        Both         II         G/A           C          cg
             orientation
                <factor>
  cg00045114        down
  cg00050294        down
  cg00066722          up
  -------
  seqinfo: 25 sequences from an unspecified genome; no seqlengths

4.5 Gene information

Gene information is stored as a GRanges object containing coordinates of each gene, gene id, gene symbol and gene isoform id. The default gene information is the ensembl gene annotation fetched from biomaRt by ELMER function.

rowRanges(getExp(data))
GRanges object with 3808 ranges and 2 metadata columns:
                  seqnames                 ranges strand |
                     <Rle>              <IRanges>  <Rle> |
  ENSG00000188984     chr1 [ 12776118,  12788726]      + |
  ENSG00000204518     chr1 [ 12704566,  12727097]      + |
  ENSG00000108270    chr17 [ 35306175,  35414171]      + |
  ENSG00000198691     chr1 [ 94458393,  94586688]      - |
  ENSG00000135776     chr1 [229652329, 229694442]      - |
              ...      ...                    ...    ... .
  ENSG00000132003    chr19   [13906274, 13943044]      + |
  ENSG00000162415     chr1   [45482071, 45771881]      - |
  ENSG00000203995     chr1   [53308183, 53360670]      + |
  ENSG00000162378     chr1   [53192126, 53293014]      + |
  ENSG00000036549     chr1   [78028101, 78149104]      - |
                  external_gene_name ensembl_gene_id
                         <character>     <character>
  ENSG00000188984            AADACL3 ENSG00000188984
  ENSG00000204518            AADACL4 ENSG00000204518
  ENSG00000108270               AATF ENSG00000108270
  ENSG00000198691              ABCA4 ENSG00000198691
  ENSG00000135776             ABCB10 ENSG00000135776
              ...                ...             ...
  ENSG00000132003             ZSWIM4 ENSG00000132003
  ENSG00000162415             ZSWIM5 ENSG00000162415
  ENSG00000203995             ZYG11A ENSG00000203995
  ENSG00000162378             ZYG11B ENSG00000162378
  ENSG00000036549               ZZZ3 ENSG00000036549
  -------
  seqinfo: 24 sequences from an unspecified genome; no seqlengths

4.6 Multi Assay Experiment object

A Multi Assay Experiment object from the MultiAssayExperiment package is the input for multiple main functions of ELMER. It contains the above components and making a Multi Assay Experiment object by createMAE function will keep each component consistent with each other. For example, althougth DNA methylation and gene expression matrixes have different rows (probe for DNA methylation and gene id for gene expression), the column (samples) order should be same in the two matrixes. The createMAE function will keep them consistent when it generates the Multi Assay Experiment object.

data <- createMAE(exp = GeneExp, 
                  met = Meth,
                  genome = "hg19",
                  save = FALSE,
                  met.platform = "450K",
                  TCGA = TRUE)

# For TGCA data 1-12 represents the patient and 1-15 represents the sample ID (i.e. primary solid tumor samples )
all(substr(colnames(getExp(data)),1,15) == substr(colnames(getMet(data)),1,15))
[1] TRUE
# See sample information for data
as.data.frame(colData(data))
# See sample names for each experiment
as.data.frame(sampleMap(data))

You can also use your own data and annotations to create Multi Assay Experiment object.

# NON TCGA example: matrices has diffetrent column names
gene.exp <- DataFrame(sample1 = c("ENSG00000141510"=2.3,"ENSG00000171862"=5.4),
                      sample2 = c("ENSG00000141510"=1.6,"ENSG00000171862"=2.3))
dna.met <- DataFrame(sample1 = c("cg14324200"=0.5,"cg23867494"=0.1),
                     sample2 =  c("cg14324200"=0.3,"cg23867494"=0.9))
sample.info <- DataFrame(sample.type = c("Normal", "Tumor"))
rownames(sample.info) <- colnames(gene.exp)

mae <- createMAE(exp = gene.exp,
                 met = dna.met,
                 save = FALSE,
                 met.platform = "450K",
                 colData = sample.info, 
                 genome = "hg38") 

# NON TCGA example: matrices has diffetrent column names
rownames(sample.info) <- c("sample1","sample2")

sampleMap <- DataFrame(primary = c("sample1","sample1","sample2","sample2"), 
                       colname = c("sample1.exp","sample1.met","sample2.exp","sample2.met"))

mae <- createMAE(exp = gene.exp, 
                 met = dna.met, 
                 sampleMap = sampleMap, 
                 colData = sample.info, 
                 save = FALSE,
                 met.platform = "450K",
                 genome = "hg38") 

5 Downloading TCGA data

The function getTCGA uses TCGAbiolinks package (A. Colaprico et al. 2015) to download TCGA data for all samples for a given disease (such as BLCA, LGG, GBM). Its main arguments are the genome that if set to “hg19” it will download data from GDC legacy archive and if set to “hg38” it will download data from the GDC harmonized data portal.

getTCGA(disease = "LUSC", # TCGA disease abbreviation (BRCA,BLCA,GBM, LGG, etc)
        basedir = "DATA", # Where data will be downloaded
        genome  = "hg38") # Genome of refenrece "hg38" or "hg19"

If the getTCGA function called before was successful it will create the following objects and folders:

--- DATA/BRCA/
  |----------- BRCA_meth_hg38.rda (object with DNA methylation)
  |----------- BRCA_RNA_hg38.rda (object with gene expression)
  |----------- BRCA_clinic.rda   (object with indexed clinical information)
  |----------- Raw/ (folder: contains All raw data from GDC)

6 Illustration of ELMER analysis steps

The example data set is a subset of chromosome 1 data from TCGA LUSC. ELMER analysis have 5 main steps which are shown below individually. TCGA.pipe introduced above is a pipeline combining all 5 steps and producing all results and figures.

6.1 Selection of probes within biofeatures

This step is to select HM450K/EPIC probes, which locate far from TSS (at least 2Kb away) These probes are called distal probes.

Be default, this comprehensive list of TSS annotated by ENSEMBL database, which is programatically accessed using biomaRt to get its last version, will be used to select distal probes. But user can use their own TSS annotation or add features such as H3K27ac ChIP-seq in a certain cell line, to select probes overlapping thoses features regions.

# get distalprobes that are 2kb away from TSS on chromosome 1
Probe <- get.feature.probe(genome = "hg19", met.platform = "450K", rm.chr = paste0("chr",c(2:22,"X","Y")))
save(Probe,file = "result/probeInfo_feature_distal.rda")

6.2 Identifying differentially methylated probes

This step is to identify DNA methylation changes at distal enhancer probes which is carried out by function get.diff.meth.

6.2.1 Description

For each distal probe, the function first rank samples from group 1 and group 2 samples by their DNA methylation beta values. To identify hypomethylated probes, the function compared the lower control quintile (20% of control samples with the lowest methylation) to the lower experiment quintile (20% of experiment samples with the lowest methylation), using an unpaired one-tailed t-test. Only the lower quintiles were used because we did not expect all cases to be from a single molecular subtype, and we sought to identify methylation changes within cases from the same molecular subtype. 20% (i.e. a quintile) was picked as a cutoff to include high enough sample numbers to yield t-test p-values that could overcome multiple hypothesis correction, yet low enough to be able to capture changes in individual molecular subtypes occurring in 20% or more of the cases. This number can be set arbitrarily as an input to the get.diff.meth function in the ELMER, and should be tuned based on sample sizes in individual studies. The one tailed t-test was used to rule out the null hypothesis: \(\mu_{experiment} \geq \mu_{control}\), where \(\mu_{experiment}\) is the mean methylation within the lowest experiment quintile and \(\mu\)control is the mean within the lowest control quintile. Raw p-values were adjusted for multiple hypothesis testing using the Benjamini-Hochberg method, and probes were selected when they had adjusted p-value less than 0.01. For additional stringency, probes were only selected if the methylation difference: \(\Delta = \mu_{experiment} - \mu_{control}\) was greater than 0.3. The same method was used to identify hypermethylated probes, except we used upper experiment quintile and upper control quintile, and chose the opposite tail in the t-test.

If save parameter of get.diff.meth is TRUE, two cvs files will be saved. If false, a data frame with the same content as the second file mentioned below will be reported.

The first file contains all statistic results for all probes which were fed into the function. Based on this file, user can change different P value or sig.dif cutoff to select the significant results without redo the analysis.

The second file contains statistic results for the probes that pass the significant criteria (P value and sig.dir).

Both files contain four columns: probe, pvalue, ExperimentMinControl, adjust.p.

  1. probe: the name of probes.
  2. pvalue: the raw P value from t-test.
  3. ExperimentMinControl: methylation difference \(\Delta\).
  4. adjust.p: adjusted P value for t-test.

6.2.2 Arguments

The main arguments of this function are:

Argument Description
data A multiAssayExperiment with DNA methylation and Gene Expression data. See createMAE function.
diff.dir A character can be “hypo” or “hyper”, showing differential methylation dirction. It can be “hypo” which is only selecting hypomethylated probes; “hyper” which is only selecting hypermethylated probes
cores A interger which defines the number of cores to be used in parallel process. Default is 1: no parallel process.
minSubgroupFrac A number ranging from 0 to 1,specifying the fraction of extreme samples from group 1 and group 2 that are used to identify the differential DNA methylation. The default is 0.2 because we typically want to be able to detect a specific (possibly unknown) molecular subtype among tumor; these subtypes often make up only a minority of samples, and 20% was chosen as a lower bound for the purposes of statistical power. If you are using pre-defined group labels, such as treated replicates vs. untreated replicated, use a value of 1.0 (Supervised mode)
pvalue A number specifies the significant P value (adjusted P value by BH) cutoff for selecting significant hypo/hyper-methylated probes. Default is 0.01
group.col A column defining the groups of the sample. You can view the available columns using: colnames(MultiAssayExperiment::colData(data)).
group1 A group from group.col. ELMER will run group1 vs group2. That means, if direction is hyper, get probes hypermethylated in group 1 compared to group 2.
group2 A group from group.col. ELMER will run group1 vs group2. That means, if direction is hyper, get probes hypermethylated in group 1 compared to group 2.
test Statistical test to be used. Options: t.test (DEFAULT), wilcox.test
sig.dif A number specifies the smallest DNA methylation difference as a cutoff for selecting significant hypo/hyper-methylated probes. Default is 0.3.
dir.out A path specify the directory for outputs. Default is is current directory.
save A logic. When TRUE, two getMethdiff.XX.csv files will be generated (see detail)

6.2.3 Code example

library(MultiAssayExperiment)
data <- createMAE(exp = GeneExp, 
                  met = Meth,
                  save = FALSE,
                  met.platform = "450K",
                  genome = "hg19",
                  TCGA = TRUE)
as.data.frame(colData(data)[1:5,])
sig.diff <- get.diff.meth(data, 
                          group.col = "definition",
                          group1 =  "Primary solid Tumor",
                          group2 = "Solid Tissue Normal",
                          minSubgroupFrac = 0.2,
                          sig.dif = 0.3,
                          diff.dir = "hypo", # Search for hypomethylated probes in group 1
                          cores = parallel::detectCores()/2, 
                          dir.out ="result", 
                          pvalue = 0.01)

as.data.frame(sig.diff)
# get.diff.meth automatically save output files. 
# getMethdiff.hypo.probes.csv contains statistics for all the probes.
# getMethdiff.hypo.probes.significant.csv contains only the significant probes which
# is the same with sig.diff
dir(path = "result", pattern = "getMethdiff")  
[1] "getMethdiff.hypo.probes.csv"            
[2] "getMethdiff.hypo.probes.significant.csv"
getMethdiff.hypo.probes.csv

getMethdiff.hypo.probes.significant.csv

6.2.4 minSubgroupFrac: Dealing with molecular subytpes

As stated before the argument minSubgroupFrac (a number ranging from 0 to 1) controls the number of samples to be used from both groups when you are comparing the DNA methylation level at each probe. When comparing Primary Solid tumor samples versus Normal tissue samples only the lower quintiles were used because we did not expect all cases to be from a single molecular subtype, and we sought to identify methylation changes within cases from the same molecular subtype. But if you are dealing already with subtypes it is better to set minSubgroupFrac to 1.

The code example below highlight some different probes founds when using 100% or 20%.

# We will evaluate the different probes found using different percentage values.
groupCol <- "subtype_Expression.Subtype"
group1 <- "classical"
group2 <- "secretory"

# For each probe use lower 20% samples
sig.diff.20 <- get.diff.meth(data, 
                             group.col = groupCol,
                             group1 = group1,
                             group2 = group2,
                             minSubgroupFrac = 0.2,
                             sig.dif = 0.3,
                             diff.dir = "hypo",
                             pvalue = 0.01)

# For each probe use all samples
sig.diff.100 <- get.diff.meth(data, 
                              group.col = groupCol,
                              group1 = group1,
                              group2 = group2,
                              minSubgroupFrac = 1.0,
                              sig.dif = 0.3,
                              diff.dir = "hypo", 
                              pvalue = 0.01)
# Which probes were found with 20% of samples and not with 100%
probe <- sig.diff.20[which(!sig.diff.20$probe %in% sig.diff.100$probe),"probe"]
metBoxPlot(data,groupCol,group1,group2,probe = probe[1],minSubgroupFrac = 0.2,
           diff.dir = "hypo", title = "probes were found with 20% of samples and not with 100%")
# Which probes were found with 100% of samples and not with 20%
probe <- sig.diff.100[which(!sig.diff.100$probe %in% sig.diff.20$probe),"probe"]
metBoxPlot(data,groupCol,group1,group2,probe = probe[1], minSubgroupFrac = 0.2, 
           diff.dir = "hypo", title = "probes were found with 100% of samples and not with 20%")

6.3 Identifying putative probe-gene pairs

This step is to link enhancer probes with methylation changes to target genes with expression changes and report the putative target gene for selected probes. This is carried out by function get.pair.

6.3.1 Description

First, the function get.pair for additional stringency and to avoid correlations due to non-cancer contamination, selects only those distal probes that had differential methylation as defined above, and where at least 5% of all samples (combining tumor and normal) had beta values > 0.3. We usually call locus unmethylated when the methylation value < 0.3 and methylated when the methylation value > 0.3. Basically, this step will make sure we have at least a percentage of beta values lesser than K and n percentage of beta values greater K. For example, if percentage is 5%, the number of samples 100 and K = 0.3, this filter will select probes that we have at least 5 (5% of 100%) samples have beta values > 0.3 and at least 5 samples have beta values < 0.3. This filter is important as true promoters and enhancers usually have a pretty low value (of course purity can screw that up).
we often see lots of PMD probes across the genome with intermediate values like 0.4.
Choosing a value of 0.3 will certainly give some false negatives, but not compared to the number of false positives we thought we might get without this filter. Please see the documentation for the function preAssociationProbeFiltering.

After, for each distal probe with differential methylation and passing this filter, the closest 10 upstream genes and the closest 10 downstream genes were tested for correlation between methylation of the probe and expression of the gene. To select these genes, the probe-gene distance was defined as the distance from the probe to a transcription start site specified by the ENSEMBL gene annotation. Thus, exactly 20 statistical tests were performed for each probe, as follows. For each probe-gene pair, the samples (all experiment samples and control samples) were divided into two groups: the M group, which consisted of the upper methylation quintile (the 20% of samples with the highest methylation at the enhancer probe), and the U group, which consisted of the lowest methylation quintile (the 20% of samples with the lowest methylation.) The 20% ile cutoff is a configurable parameter in the get.pair. Default is 20% as a balance, which would allow us to identify changes in a molecular subtype making up a minority (i.e. 20%) of cases, while also yielding enough statistical power to make strong predictions. For each candidate probe-gene pair, the Mann-Whitney U test was used to test the null hypothesis that overall gene expression in group M was greater or equal than that in group U. This non-parametric test was used in order to minimize the effects of expression outliers, which can occur across a very wide dynamic range. For each probe-gene pair tested, the raw p-value Pr was corrected for multiple hypothesis using a permutation approach as follows (implemented in the get.permu function of the ELMER package). The gene in the pair was held constant, and x random methylation probes were used to perform the same one-tailed U test, generating a set of x permutation p-values (Pp). We chose the x random probes only from among those that were “distal” (greater than 2kb from an annotated transcription start site), in order to make these null-model probes qualitatively similar to the probe being tested. An empirical p-value \(P_e\) value was calculated using the following formula (which introduces a pseudo-count of 1):

\[Pe = \frac{num(P_p \leq P_r)+ 1}{x+1}\]

This step is the most time consuming step since it requires a large amount calculations for permutation. The greater the permutation time is, the longer it will take. It is recommended to use multiple cores for this step. 10,000 permutations is recommended if high confidence results are desired but it may cost some hours.

If save parameter of get.pair function is true, two cvs files will be output. If save parameter is false, a data frame with the same contect as the second file mentioned as below will be output.

The first file contains all statistic results for all probe-gene pairs. Based on this file, user can change different P value or sig.dir cutoff to select the significant results without redo the analysis.

The second file contains statistic results for the probes that pass the significant criteria (Pe).

Both files contain four columns: probe, GeneID, Symbol, Distance, Sides, Raw.p, Pe.

  1. Probe: the name of probes.
  2. GeneID and Symbol is for the genes which are linked to the probe.
  3. Distance: the distance between the probe and the gene.
  4. Sides: right (R) side or left (L) side of probe and the rank based on distance. For example, L3 means the gene is the number 3 closest gene from the left side of the probe.
  5. Raw.p: P value from the Mann-Whitney U test for each pair.
  6. Pe: the empirical P value for each pair.

6.3.2 Arguments

The main arguments of this function are:

Argument Description
data A multiAssayExperiment with DNA methylation and Gene Expression data. See createMAE function.
nearGenes Can be either a list containing output of GetNearGenes function or path of rda file containing output of GetNearGenes function.
minSubgroupFrac A number ranging from 0 to 1.0 specifying the percentage of samples used to create groups U (unmethylated) and M (methylated) used to link probes to genes. Default is 0.4 (lowest quintile samples will be in the U group and the highest quintile samples in the M group).
permu.size A number specify the times of permuation. Default is 10000.
permu.dir A path where the output of permutation will be.
pvalue A number specify the raw p-value cutoff for defining signficant pairs. Default is 0.05. It will select the significant P value cutoff before calculating the empirical p-values.
Pe A number specify the empirical p-value cutoff for defining signficant pairs. Default is 0.001.
dir.out A path specify the directory for outputs. Default is current directory
diffExp A logic. Default is FALSE. If TRUE, t test will be applied to test whether putative target gene are differentially expressed between two groups.
group.col A column defining the groups of the sample. You can view the available columns using: colnames(MultiAssayExperiment::colData(data)).
group1 A group from group.col.
group2 A group from group.col.
cores A interger which defines number of core to be used in parallel process. Default is 1: don’t use parallel process.
filter.probes Should filter probes by selecting only probes that have at least a certain number of samples below and above a certain cut-off. See preAssociationProbeFiltering function.
filter.portion A number specify the cut point to define binary methlation level for probe loci. Default is 0.3. When beta value is above 0.3, the probe is methylated and vice versa. For one probe, the percentage of methylated and unmethylated samples should be above filter.percentage value. Only used if filter.probes is TRUE. See preAssociationProbeFiltering function.
filter.percentage Minimum percentage of samples to be considered in methylated and unmethylated for the filter.portion option. Default 5%. Only used if filter.probes is TRUE. See preAssociationProbeFiltering function.
label A character labels the outputs.
save Two files will be saved if save is true: getPair.XX.all.pairs.statistic.csv and getPair.XX.pairs.significant.csv (see detail).

6.3.3 Code example

### identify target gene for significantly hypomethylated probes.

Sig.probes <- read.csv("result/getMethdiff.hypo.probes.significant.csv",
                       stringsAsFactors=FALSE)[,1]  
head(Sig.probes)  # significantly hypomethylated probes
[1] "cg00045114" "cg00050294" "cg00093522" "cg00163018" "cg00173804"
[6] "cg00223046"
cg00045114

cg00050294

cg00093522

cg00163018

cg00173804

cg00223046
## Collect nearby 20 genes for Sig.probes
nearGenes <- GetNearGenes(data = data, 
                          probes = Sig.probes, 
                          numFlankingGenes = 20, # 10 upstream and 10 dowstream genes
                          cores = parallel::detectCores()/2)

## Identify significant probe-gene pairs
Hypo.pair <- get.pair(data = data,
                      group.col = "definition",
                      group1 =  "Primary solid Tumor",
                      group2 = "Solid Tissue Normal",
                      nearGenes = nearGenes,
                      minSubgroupFrac = 0.4, # % of samples to use in to create groups U/M
                      permu.dir = "result/permu",
                      permu.size = 100, # Please set to 100000 to get significant results
                      pvalue = 0.05,   
                      Pe = 0.01,       # Please set to 0.001 to get significant results
                      filter.probes = TRUE, # See preAssociationProbeFiltering function
                      filter.percentage = 0.05,
                      filter.portion = 0.3,
                      dir.out = "result",
                      cores = parallel::detectCores()/2,
                      label = "hypo")

datatable(Hypo.pair, ## significant probe-gene pairs
          options = list(scrollX = TRUE, keys = TRUE, pageLength = 5), 
          rownames = TRUE)

# get.pair automatically save output files. 
#getPair.hypo.all.pairs.statistic.csv contains statistics for all the probe-gene pairs.
#getPair.hypo.pairs.significant.csv contains only the significant probes which is 
# same with Hypo.pair.
dir(path = "result", pattern = "getPair") 
[1] "getPair.hypo.all.pairs.statistic.csv"                  
[2] "getPair.hypo.pairs.significant.csv"                    
[3] "getPair.hypo.pairs.significant.withmotif.csv"          
[4] "getPair.hypo.pairs.statistic.with.empirical.pvalue.csv"
getPair.hypo.all.pairs.statistic.csv

getPair.hypo.pairs.significant.csv

getPair.hypo.pairs.significant.withmotif.csv

getPair.hypo.pairs.statistic.with.empirical.pvalue.csv

6.4 Motif enrichment analysis on the selected probes

This step is to identify enriched motif in a set of probes which is carried out by function get.enriched.motif.

6.4.1 Description

The build-in data Probes.motif is generated using HOMER with a \(p-value \le 10^{–4}\) to scan a \(\pm250bp\) region around each probe using HOmo sapiens COmprehensive MOdel COllection http://hocomoco.autosome.ru/ v10 (Kulakovskiy et al. 2016) position weight matrices (PWMs). HOCOMOCO offers 601 PMWs each has a quality rating from A to D where A represents motifs with the highest confidence, and D motifs only weakly describe the pattern with a limited applications for quantitative analyses. By default only quality A and B will be used for the Motif enrichment analysis, but the Minimum quality score can be selected by the user. (Addtional information http://hocomoco.autosome.ru/help#description_quality_score
http://nar.oxfordjournals.org/content/44/D1/D116.full#sec-8).

For each probe set tested (i.e. the list of gene-linked hypomethylated probes in a given experiment group), a motif enrichment Odds Ratio and a 95% confidence interval were calculated using following formulas: \[ p= \frac{a}{a+b} \] \[ P= \frac{c}{c+d} \] \[ Odds\quad Ratio = \frac{\frac{p}{1-p}}{\frac{P}{1-P}} \] \[ SD = \sqrt{\frac{1}{a}+\frac{1}{b}+\frac{1}{c}+\frac{1}{d}} \] \[ lower\quad boundary\quad of\quad 95\%\quad confidence\quad interval = \exp{(\ln{OR}-SD)} \]

where a is the number of probes within the selected probe set that contain one or more motif occurrences; b is the number of probes within the selected probe set that do not contain a motif occurrence; c and d are the same counts within the entire enhancer probe set. A probe set was considered significantly enriched for a particular motif if the 95% confidence interval of the Odds Ratio was greater than 1.1 (specified by option lower.OR, 1.1 is default), and the motif occurred at least 10 times (specified by option min.incidence. 10 is default) in the probe set. As described in the text, Odds Ratios were also used for ranking candidate motifs.

There will be two results if save parameter of get.enriched.motif is TRUE. When save is FALSE, only second result mentioned below will be reported.

The first one is a csv file. This file contains the Odds Ratio and 95% confidence interval for these Odds Ratios which pass the signficant cutoff (lower.OR and min.incidence). It contains 5 columns: motif, NumOfProbes, OR, lowerOR and upperOR.

  1. motif: the name of motif.
  2. NumOfProbes: the number of probes with this motif in the given set of probes corresponding to min.incidence option.
  3. OR: the Odds Ratio.
  4. lowerOR: the lower boundary of 95% confidence interval.
  5. upperOR: the upper boundary of 95% confidence interval.

The second file is a rda file listing each enriched motif and the probes containing the motif.

6.4.2 Arguments

The main arguments of this function are:

Argument Description
data A multi Assay Experiment from createMAE function. If set and probes.motif/background probes are missing this will be used to get this other two arguments correctly. This argument is not require, you can set probes.motif and the backaground.probes manually.
probes.motif A matrix contains motifs occurrence within probes regions. Probes.motif in ELMER.data will be used if probes.motif is missing (detail see Probes.motif.hg19.450K).
probes A vector lists the name of probes to define the set of probes in which motif enrichment OR and confidence interval will be calculated.
min.motif.quality Minimum motif quality score to consider. Possible valules: A, B, C , D, AS (A and S), BS (A, B and S), CS (A, B , C and S), DS (all - default) Description: Each PWM has a quality rating from A to D where A represents motifs with the highest confidence, and D motifs only weakly describe the pattern with a limited applications for quantitative analyses. Special S quality marks the single-box motifs (secondary motif). Source: http://hocomoco.autosome.ru/help#description_quality_score More information: http://nar.oxfordjournals.org/content/44/D1/D116.full#sec-8
background.probes A vector lists name of probes which are considered as background for motif.enrichment calculation (see detail).
lower.OR A number specifies the smallest lower boundary of 95% confidence interval for Odds Ratio. The motif with higher lower boudnary of 95% confidence interval for Odds Ratio than the number are the significantly enriched motifs (detail see reference).
min.incidence A non-negative integer specifies the minimum incidence of motif in the given probes set. 10 is default.
dir.out A path. Specifies the directory for outputs. Default is current directory
label A character. Labels the outputs such as “hypo”, “hyper”
save If save is TURE, two files will be saved: getMotif.XX.enriched.motifs.rda and getMotif.XX.motif.enrichment.csv (see detail).

6.4.3 Code example

## identify enriched motif for significantly hypomethylated probes which 
##have putative target genes.

Sig.probes.paired <- read.csv("result/getPair.hypo.pairs.significant.csv",
                              stringsAsFactors=FALSE)[,1]  
head(Sig.probes.paired) # significantly hypomethylated probes with putative target genes
[1] "cg20701183" "cg19403323" "cg12213388" "cg26607897" "cg10574861"
[6] "cg26607897"
cg20701183

cg19403323

cg12213388

cg26607897

cg10574861

cg26607897
enriched.motif <- get.enriched.motif(data = data,
                                     min.motif.quality = "B", # Default: options A, B, C, D
                                     probes = Sig.probes.paired, 
                                     dir.out = "result", 
                                     label = "hypo",
                                     min.incidence = 10,
                                     lower.OR = 1.1)
names(enriched.motif)  # enriched motifs
 [1] "CEBPA_HUMAN.H10MO.A" "EVX2_HUMAN.H10MO.A"  "FOSL1_HUMAN.H10MO.A"
 [4] "FOSL2_HUMAN.H10MO.A" "FOS_HUMAN.H10MO.A"   "FOXJ3_HUMAN.H10MO.A"
 [7] "IRF1_HUMAN.H10MO.A"  "JUND_HUMAN.H10MO.A"  "JUN_HUMAN.H10MO.A"  
[10] "NANOG_HUMAN.H10MO.A" "NFAC2_HUMAN.H10MO.B" "NFAC3_HUMAN.H10MO.B"
[13] "P73_HUMAN.H10MO.A"   "PBX1_HUMAN.H10MO.B"  "PO2F1_HUMAN.H10MO.B"
[16] "SOX2_HUMAN.H10MO.B"  "SRY_HUMAN.H10MO.B"   "STAT1_HUMAN.H10MO.A"
[19] "STAT2_HUMAN.H10MO.B"
CEBPA_HUMAN.H10MO.A

EVX2_HUMAN.H10MO.A

FOSL1_HUMAN.H10MO.A

FOSL2_HUMAN.H10MO.A

FOS_HUMAN.H10MO.A

FOXJ3_HUMAN.H10MO.A

IRF1_HUMAN.H10MO.A

JUND_HUMAN.H10MO.A

JUN_HUMAN.H10MO.A

NANOG_HUMAN.H10MO.A

NFAC2_HUMAN.H10MO.B

NFAC3_HUMAN.H10MO.B

P73_HUMAN.H10MO.A

PBX1_HUMAN.H10MO.B

PO2F1_HUMAN.H10MO.B

SOX2_HUMAN.H10MO.B

SRY_HUMAN.H10MO.B

STAT1_HUMAN.H10MO.A

STAT2_HUMAN.H10MO.B
head(enriched.motif["P73_HUMAN.H10MO.A"]) ## probes in the given set that have TP53 motif.
$P73_HUMAN.H10MO.A
 [1] "cg24729839" "cg19896129" "cg13487474" "cg11157208" "cg15714328"
 [6] "cg24296187" "cg25199536" "cg14420230" "cg18795022" "cg23981702"
[11] "cg20701183" "cg00329272" "cg18437839" "cg16578549" "cg15895782"
[16] "cg18857402" "cg24558378" "cg26883161" "cg01791421" "cg23972860"
[21] "cg21690505" "cg20146241" "cg23230478" "cg00935967" "cg18395632"
[26] "cg17181043" "cg21686171" "cg22684969" "cg12458003" "cg17907003"
[31] "cg24310780" "cg09814448"
cg24729839

cg19896129

cg13487474

cg11157208

cg15714328

cg24296187

cg25199536

cg14420230

cg18795022

cg23981702

cg20701183

cg00329272

cg18437839

cg16578549

cg15895782

cg18857402

cg24558378

cg26883161

cg01791421

cg23972860

cg21690505

cg20146241

cg23230478

cg00935967

cg18395632

cg17181043

cg21686171

cg22684969

cg12458003

cg17907003

cg24310780

cg09814448
# get.enriched.motif automatically save output files. 
# getMotif.hypo.enriched.motifs.rda contains enriched motifs and the probes with the motif. 
# getMotif.hypo.motif.enrichment.csv contains summary of enriched motifs.
dir(path = "result", pattern = "getMotif") 
[1] "getMotif.hypo.enriched.motifs.rda" 
[2] "getMotif.hypo.motif.enrichment.csv"
getMotif.hypo.enriched.motifs.rda

getMotif.hypo.motif.enrichment.csv
# motif enrichment figure will be automatically generated.
dir(path = "result", pattern = "motif.enrichment.pdf") 
[1] "hypo.all.quality.motif.enrichment.pdf"
[2] "hypo.quality.A-B.motif.enrichment.pdf"
hypo.all.quality.motif.enrichment.pdf

hypo.quality.A-B.motif.enrichment.pdf

6.5 Identifying regulatory TFs

This step is to identify regulatory TF whose expression associates with TF binding motif DNA methylation which is carried out by function get.TFs.

6.5.1 Description

For each motif considered to be enriched within a particular probe set, function will compare the average DNA methylation at all distal enhancer probes within \(\pm250bp\)
of a motif occurrence, to the expression of human TFs. A statistical test was performed for each motif-TF pair, as follows. The samples (all control and experiment samples) were divided into two groups: the M group, which consisted of the 20% of samples with the highest average methylation at all motif-adjacent probes, and the U group, which consisted of the 20% of samples with the lowest methylation. The 20th percentile cutoff is a parameter to the get.TFs function and was set to allow for identification of molecular subtypes present in 20% of cases. For each candidate motif-TF pair, the Mann-Whitney U test was used to test the null hypothesis that overall gene expression in group M was greater or equal than that in group U. This non-parametric test was used in order to minimize the effects of expression outliers, which can occur across a very wide dynamic range. For each motif tested, this resulted in a raw p-value (\(P_r\)) for each of the human TFs. All TFs were ranked by the \(-log_{10}(P_{r})\), and those falling within the top 5% of this ranking were considered candidate upstream regulators. The best upstream TFs which are known recognized the motif was automatically extracted as putative regulatory TFs.

If save parameter of get.TFs function is true, two files will be generated. If save parameter is FALSE, only a data frame containing the same content with the first file mentioned below will be output.

The first one csv file. This file contain the regulatory TF significantly associate with average DNA methylation at particular motif sites. It contains 6 columns: motif, top.potential.TF.family, top.potential.TF.subfamily, potential.TFs.family, potential.TFs.subfamily and top_5percent.

  1. motif: the names of motif.
  2. top.potential.TF.family: the highest ranking upstream TFs which are known recognized the motif. First item in potential.TFs.family
  3. top.potential.TF.subfamily: the highest ranking upstream TFs which are known recognized the motif. First item in potential.TFs.subfamily
  4. potential.TFs.family: TFs which are within top 5% list and are known recognized the motif (considering family classification).
  5. potential.TFs.subfamily: TFs which are within top 5% list and are known recognized the motif (considering subfamily classification).
  6. top_5percent: all TFs which are within top 5% list.

The second file is rda file. This file contains a matrix storing the statistic results for associations between TFs (row) and average DNA methylation at motifs (column). This matrix can be use to generate TF ranking plots by function TF.rank.plot.

6.5.2 Arguments

The main arguments of this function are:

Argument Description
data A multiAssayExperiment with DNA methylation and Gene Expression data. See createMAE function.
enriched.motif A list containing output of get.enriched.motif function or a path of XX.rda file containing output of get.enriched.motif function.
TFs A data.frame containing TF GeneID and Symbol or a path of XX.csv file containing TF GeneID and Symbol. If missing, human.TF list will be used (human.TF data in ELMER.data). For detail information, refer the reference paper.
motif.relevant.TFs A list containing motif as names and relavent TFs as contents for each list element or a path of XX.rda file containing a list as above. If missing, TFClass classification will be used. See function createMotifRelevantTfs
group.col A column defining the groups of the sample. You can view the available columns using: colnames(MultiAssayExperiment::colData(data)).
group1 A group from group.col.
group2 A group from group.col.
minSubgroupFrac A number ranging from 0 to 1 specifying the percentage of samples used to create the groups U (unmethylated) and M (methylated) used to link probes to TF expression. Default is 0.4 (lowest quintile of all samples will be in the U group and the highest quintile of all samples in the M group).
dir.out A path specifies the directory for outputs of get.pair function. Default is current directory
label A character labels the outputs.
cores A interger which defines the number of cores to be used in parallel process. Default is 1: no parallel process.
save A logic. If save is ture, two files will be saved: getTF.XX.significant.TFs.with.motif.summary.csv and getTF.hypo.TFs.with.motif.pvalue.rda (see detail). If save is false, a data frame contains the same content with the first file.

6.5.3 Code example

## identify regulatory TF for the enriched motifs
TF <- get.TFs(data = data, 
              group.col = "definition",
              group1 =  "Primary solid Tumor",
              group2 = "Solid Tissue Normal",
              minSubgroupFrac = 1.0,
              enriched.motif = enriched.motif,
              dir.out = "result", 
              cores = 1, 
              label = "hypo")

# get.TFs automatically save output files. 
# getTF.hypo.TFs.with.motif.pvalue.rda contains statistics for all TF with average 
# DNA methylation at sites with the enriched motif.
# getTF.hypo.significant.TFs.with.motif.summary.csv contains only the significant probes.
dir(path = "result", pattern = "getTF")  

# TF ranking plot based on statistics will be automatically generated.
dir(path = "result/TFrankPlot_family/", pattern = "pdf") 

7 Generating figures

7.1 Scatter plots

Generate scatter plots for one probes’ nearby 20 gene expression vs DNA methylation at this probe.

Each scatter plot shows the methylation level of an example probe cg19403323 in all LUSC samples plotted against the expression of one of 20 adjacent genes.

scatter.plot(data,
             byProbe = list(probe = c("cg19403323"), numFlankingGenes = 20), 
             category = "definition", 
             lm = TRUE, # Draw linear regression curve
             save = FALSE) 
Each scatter plot shows the methylation level of an example  probe cg19403323 in all LUSC samples plotted against the expression of one of  20 adjacent genes.

Each scatter plot shows the methylation level of an example probe cg19403323 in all LUSC samples plotted against the expression of one of 20 adjacent genes.

7.1.1 Scatter plot of one pair

Generate a scatter plot for one probe-gene pair. Figure

Scatter plot shows the methylation level of an example probe cg19403323 in all LUSC samples plotted against the expression of the putative target gene SYT14.

scatter.plot(data,
             byPair = list(probe = c("cg19403323"), gene = c("ENSG00000143469")), 
             category = "definition", save = TRUE, lm_line = TRUE) 
Scatter plot shows the methylation level of an example probe cg19403323 in all LUSC samples plotted against the expression of the putative  target gene SYT14.

Scatter plot shows the methylation level of an example probe cg19403323 in all LUSC samples plotted against the expression of the putative target gene SYT14.

7.1.2 TF expression vs. average DNA methylation

Generate scatter plot for TF expression vs average DNA methylation of the sites with certain motif.

Each scatter plot shows the average methylation level of sites with the TP53 motif in all LUSC samples plotted against the expression of the transcription factor TP53, TP63, TP73 respectively.

load("result/getMotif.hypo.enriched.motifs.rda")
scatter.plot(data,
             byTF = list(TF = c("TP53","TP63","TP73"),
                         probe = enriched.motif[["P73_HUMAN.H10MO.A"]]), 
             category = "definition",
             save = TRUE, 
             lm_line = TRUE)
Each scatter plot shows the average  methylation level of sites with the TP53 motif in all LUSC samples plotted against the expression of the transcription factor TP53, TP63, TP73 respectively.

Each scatter plot shows the average methylation level of sites with the TP53 motif in all LUSC samples plotted against the expression of the transcription factor TP53, TP63, TP73 respectively.

7.2 Schematic plot

Schematic plot shows a breif view of linkages between genes and probes.

7.2.1 Nearby Genes

Generate schematic plot for one probe with 20 nearby genes and label the gene significantly linked with the probe in red.

schematic.plot(pair = Hypo.pair, 
               data = data,
               group.col = "definition",
               byProbe = "cg25312122",
               save = FALSE)
The schematic plot shows probe colored in blue and the location of nearby 20 genes. The genes significantly linked to the probe  were shown in red.

The schematic plot shows probe colored in blue and the location of nearby 20 genes. The genes significantly linked to the probe were shown in red.

7.2.2 Nearby Probes

Generate schematic plot for one gene with the probes which the gene is significantly linked to.

schematic.plot(pair = Hypo.pair, 
               data = data,   
               group.col = "definition", 
               byGene = "ENSG00000143469", 
               save = FALSE)
The schematic plot shows the gene colored in red and all blue colored probes, which are significantly linked to the  expression of this gene.

The schematic plot shows the gene colored in red and all blue colored probes, which are significantly linked to the expression of this gene.

7.3 Motif enrichment plot

Motif enrichment plot shows the enrichment levels for the selected motifs.

The plot shows the Odds Ratio (x axis) for the selected motifs with OR above 1.3 and lower boundary of OR above 1.3. The range shows the 95% confidence interval for each Odds Ratio

motif.enrichment.plot(motif.enrichment = "result/getMotif.hypo.motif.enrichment.csv", 
                      significant = list(OR = 1.3,lowerOR = 1.3), 
                      label = "hypo", 
                      save = TRUE)  ## different signficant cut off.
The plot shows the Odds Ratio (x axis) for the selected motifs with OR above 1.3 and lower boundary of OR above 1.3. The range shows the 95% confidence interval for each Odds Ratio.

The plot shows the Odds Ratio (x axis) for the selected motifs with OR above 1.3 and lower boundary of OR above 1.3. The range shows the 95% confidence interval for each Odds Ratio.

7.4 TF ranking plot

TF ranking plot shows statistic \(-log_{10}(P value)\) assessing the anti-correlation level of TFs expression level with average DNA methylation level at sites with a given motif. By default, the top 3 associated TFs and the TF family members (dots in red) that are associated with that specific motif are labeled in the plot. But there is also a option show highlight only TF sub-family members (TCClass database classification)

Shown are TF ranking plots based on the score (\(-log_{10}(P value))\) of association between TF expression and DNA methylation of the P73 motif in the LUSC cancer type. The dashed line indicates the boundary of the top 5% association score. The top 3 associated TFs and the TF family members=(dots in red) that are associated with that specific motif are labeled in the plot

load("result/getTF.hypo.TFs.with.motif.pvalue.rda")
motif <- "P73_HUMAN.H10MO.A"
TF.rank.plot(motif.pvalue = TF.meth.cor, 
             motif = motif,
             save = FALSE) 
Accessing hocomoco to get last version of TFs family
$P73_HUMAN.H10MO.A
Shown are TF ranking plots based on the score (-log(P value)) of association between TF expression and DNA methylation of the P73 motif in the LUSC cancer type. The dashed line indicates the boundary of the top 5% association score. The top 3 associated TFs and the TF family members=(dots in red) that are associated with that specific motif are labeled in the plot

Shown are TF ranking plots based on the score (-log(P value)) of association between TF expression and DNA methylation of the P73 motif in the LUSC cancer type. The dashed line indicates the boundary of the top 5% association score. The top 3 associated TFs and the TF family members=(dots in red) that are associated with that specific motif are labeled in the plot

Shown are TF ranking plots based on the score (\(-log_{10}(P value)\)) of association between TF expression and DNA methylation of the P73 motif in the LUSC cancer type. The dashed line indicates the boundary of the top 5% association score. The top 3 associated TFs and the TF sub-family members=(dots in red) that are associated with that specific motif are labeled in the plot.

load("result/getTF.hypo.TFs.with.motif.pvalue.rda")
motif <- "P73_HUMAN.H10MO.A"
TF.rank.plot(motif.pvalue = TF.meth.cor,  
            motif = motif, 
            TF.label = createMotifRelevantTfs("subfamily")[motif],
            save = FALSE)
Accessing hocomoco to get last version of TFs subfamily
$P73_HUMAN.H10MO.A
Shown are TF ranking plots based on the score (-log(P value)) of association between TF expression and DNA methylation of the P73 motif in the LUSC cancer type. The dashed line indicates the boundary of the top 5% association score. The top 3 associated TFs and the TF sub-family members=(dots in red) that are associated with that specific motif are labeled in the plot

Shown are TF ranking plots based on the score (-log(P value)) of association between TF expression and DNA methylation of the P73 motif in the LUSC cancer type. The dashed line indicates the boundary of the top 5% association score. The top 3 associated TFs and the TF sub-family members=(dots in red) that are associated with that specific motif are labeled in the plot

8 Session Information


sessionInfo()
R version 3.4.0 (2017-04-21)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Sierra 10.12.4

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.4/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] parallel  stats4    stats     graphics  grDevices utils     datasets 
[8] methods   base     

other attached packages:
 [1] webshot_0.4.1              bindrcpp_0.1              
 [3] SummarizedExperiment_1.6.3 DelayedArray_0.2.7        
 [5] matrixStats_0.52.2         Biobase_2.36.2            
 [7] GenomicRanges_1.28.3       GenomeInfoDb_1.12.2       
 [9] IRanges_2.10.2             S4Vectors_0.14.3          
[11] BiocGenerics_0.22.0        MultiAssayExperiment_1.2.1
[13] DT_0.2                     BiocStyle_2.4.0           
[15] ELMER_2.0.0                ELMER.data_2.0.0          

loaded via a namespace (and not attached):
  [1] shinydashboard_0.6.0          R.utils_2.5.0                
  [3] htmlwidgets_0.8               RSQLite_1.1-2                
  [5] AnnotationDbi_1.38.1          grid_3.4.0                   
  [7] trimcluster_0.1-2             BiocParallel_1.10.1          
  [9] devtools_1.13.2.9000          DESeq_1.28.0                 
 [11] munsell_0.4.3                 codetools_0.2-15             
 [13] withr_1.0.2                   colorspace_1.3-2             
 [15] GOSemSim_2.2.0                BiocInstaller_1.26.0         
 [17] highr_0.6                     knitr_1.16                   
 [19] supraHex_1.14.0               robustbase_0.92-7            
 [21] DOSE_3.2.0                    pathview_1.16.0              
 [23] labeling_0.3                  KEGGgraph_1.34.0             
 [25] GenomeInfoDbData_0.99.0       mnormt_1.5-5                 
 [27] hwriter_1.3.2                 KMsurv_0.1-5                 
 [29] rprojroot_1.2                 downloader_0.4               
 [31] biovizBase_1.24.0             ggthemes_3.4.0               
 [33] EDASeq_2.10.0                 diptest_0.75-7               
 [35] R6_2.2.1                      doParallel_1.0.10            
 [37] locfit_1.5-9.1                AnnotationFilter_1.0.0       
 [39] flexmix_2.3-14                bitops_1.0-6                 
 [41] reshape_0.8.6                 fgsea_1.2.1                  
 [43] assertthat_0.2.0              scales_0.4.1                 
 [45] nnet_7.3-12                   gtable_0.2.0                 
 [47] ensembldb_2.0.3               rlang_0.1.1.9000             
 [49] genefilter_1.58.1             cmprsk_2.2-7                 
 [51] GlobalOptions_0.0.12          splines_3.4.0                
 [53] rtracklayer_1.36.3            lazyeval_0.2.0               
 [55] acepack_1.4.1                 dichromat_2.0-0              
 [57] hexbin_1.27.1                 selectr_0.3-1                
 [59] checkmate_1.8.2               broom_0.4.2                  
 [61] yaml_2.1.14                   reshape2_1.4.2               
 [63] crosstalk_1.0.0               GenomicFeatures_1.28.3       
 [65] backports_1.1.0               httpuv_1.3.3                 
 [67] qvalue_2.8.0                  Hmisc_4.0-3                  
 [69] clusterProfiler_3.4.3         tools_3.4.0                  
 [71] psych_1.7.5                   ggplot2_2.2.1                
 [73] RColorBrewer_1.1-2            Rcpp_0.12.11                 
 [75] plyr_1.8.4                    base64enc_0.1-3              
 [77] zlibbioc_1.22.0               purrr_0.2.2.2                
 [79] RCurl_1.95-4.8                ggpubr_0.1.3.999             
 [81] rpart_4.1-11                  GetoptLong_0.1.6             
 [83] viridis_0.4.0                 zoo_1.8-0                    
 [85] ggrepel_0.6.5                 cluster_2.0.6                
 [87] magrittr_1.5                  data.table_1.10.4            
 [89] DO.db_2.9                     circlize_0.4.0               
 [91] survminer_0.4.0.999           mvtnorm_1.0-6                
 [93] whisker_0.3-2                 ProtGenerics_1.8.0           
 [95] pkgload_0.0.0.9000            aroma.light_3.6.0            
 [97] mime_0.5                      hms_0.3                      
 [99] evaluate_0.10                 xtable_1.8-2                 
[101] XML_3.98-1.7                  mclust_5.3                   
[103] gridExtra_2.2.1               shape_1.4.2                  
[105] testthat_1.0.2                compiler_3.4.0               
[107] biomaRt_2.32.1                tibble_1.3.3                 
[109] crayon_1.3.2                  R.oo_1.21.0                  
[111] htmltools_0.3.6               Formula_1.2-1                
[113] tidyr_0.6.3                   geneplotter_1.54.0           
[115] DBI_0.6-1                     matlab_1.0.2                 
[117] ComplexHeatmap_1.14.0         MASS_7.3-47                  
[119] GenomicInteractions_1.10.0    fpc_2.1-10                   
[121] ShortRead_1.34.0              Matrix_1.2-10                
[123] readr_1.1.1                   R.methodsS3_1.7.1            
[125] bindr_0.1                     Gviz_1.20.0                  
[127] igraph_1.0.1                  km.ci_0.5-2                  
[129] rvcheck_0.0.8                 GenomicAlignments_1.12.1     
[131] foreign_0.8-68                plotly_4.7.0                 
[133] InteractionSet_1.4.0          xml2_1.1.1                   
[135] foreach_1.4.3                 annotate_1.54.0              
[137] XVector_0.16.0                rvest_0.3.2                  
[139] VariantAnnotation_1.22.1      stringr_1.2.0                
[141] digest_0.6.12                 ConsensusClusterPlus_1.40.0  
[143] graph_1.54.0                  Biostrings_2.44.1            
[145] rmarkdown_1.5                 fastmatch_1.1-0              
[147] htmlTable_1.9                 TCGAbiolinks_2.5.4           
[149] survMisc_0.5.4                dendextend_1.5.2             
[151] edgeR_3.18.1                  curl_2.6                     
[153] kernlab_0.9-25                shiny_1.0.3.9000             
[155] Rsamtools_1.28.0              modeltools_0.2-21            
[157] rjson_0.2.15                  nlme_3.1-131                 
[159] jsonlite_1.5                  BSgenome_1.44.0              
[161] viridisLite_0.2.0             limma_3.32.2                 
[163] lattice_0.20-35               KEGGREST_1.16.0              
[165] httr_1.2.1                    DEoptimR_1.0-8               
[167] pkgbuild_0.0.0.9000           survival_2.41-3              
[169] GO.db_3.4.1                   interactiveDisplayBase_1.14.0
[171] glue_1.1.0                    UpSetR_1.3.3                 
[173] png_0.1-7                     prabclus_2.2-6               
[175] iterators_1.0.8               Rgraphviz_2.20.0             
[177] class_7.3-14                  stringi_1.1.5                
[179] AnnotationHub_2.8.2           latticeExtra_0.6-28          
[181] memoise_1.1.0                 dplyr_0.7.0                  
[183] ape_4.1                      

9 References

Durinck, Steffen, Paul T Spellman, Ewan Birney, and Wolfgang Huber. 2009. “Mapping Identifiers for the Integration of Genomic Datasets with the R/Bioconductor Package BiomaRt.” Nature Protocols 4 (8). Nature Publishing Group: 1184–91.

Kulakovskiy, Ivan V, Ilya E Vorontsov, Ivan S Yevshin, Anastasiia V Soboleva, Artem S Kasianov, Haitham Ashoor, Wail Ba-Alawi, et al. 2016. “HOCOMOCO: Expansion and Enhancement of the Collection of Transcription Factor Binding Sites Models.” Nucleic Acids Research 44 (D1). Oxford Univ Press: D116–D125.

Silva, TC, A Colaprico, C Olsen, F D’Angelo, G Bontempi, M Ceccarelli, and H Noushmehr. 2016. “TCGA Workflow: Analyze Cancer Genomics and Epigenomics Data Using Bioconductor Packages [Version 2; Referees: 1 Approved, 2 Approved with Reservations].” F1000Research 5 (1542). doi:10.12688/f1000research.8923.2.

Yates, Andrew, Wasiu Akanni, M Ridwan Amode, Daniel Barrell, Konstantinos Billis, Denise Carvalho-Silva, Carla Cummins, et al. 2015. “Ensembl 2016.” Nucleic Acids Research. Oxford Univ Press, gkv1157.

Zhou, Wanding, Peter W Laird, and Hui Shen. 2016. “Comprehensive Characterization, Annotation and Innovative Use of Infinium Dna Methylation Beadchip Probes.” Nucleic Acids Research. Oxford Univ Press, gkw967.

LS0tCnRpdGxlOiAiRUxNRVI6IEFuIFIvQmlvY29uZHVjdG9yIFRvb2wgSW5mZXJyaW5nIFJlZ3VsYXRvcnkgRWxlbWVudCBMYW5kc2NhcGVzIGFuZCBUcmFuc2NyaXB0aW9uIEZhY3RvciBOZXR3b3JrcyBVc2luZyBNZXRoeWxvbWVzIgphdXRob3I6ICJMaWppbmcgWWFvLCBCZW4gQmVybWFuIFthdXRdLCBQZWdneSBGYXJuaGFtIFthdXRdSHVpIFNoZW4gW2N0Yl0sIFBldGVyIExhaXJkIFtjdGJdLCBTaW1vbiBDb2V0emVlIFtjdGJdLCBUaWFnbyBDaGVkcmFvdWkgU2lsdmEgW2N0Yl0iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiB5ZXMKICAgIGZpZ19jYXB0aW9uOiB5ZXMgICAgIAogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICBlZGl0b3Jfb3B0aW9uczogCiAgICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lICAgCgpiaWJsaW9ncmFwaHk6IGJpYmxpb2dyYXBoeS5iaWIKdmlnbmV0dGU6ID4KICAlXFZpZ25ldHRlSW5kZXhFbnRyeXsiRUxNRVI6IEFuIFIvQmlvY29uZHVjdG9yIFRvb2wgSW5mZXJyaW5nIFJlZ3VsYXRvcnkgRWxlbWVudCBMYW5kc2NhcGVzIGFuZCBUcmFuc2NyaXB0aW9uIEZhY3RvciBOZXR3b3JrcyBVc2luZyBNZXRoeWxvbWVzIn0KICAlXFZpZ25ldHRlRW5naW5le2tuaXRyOjpybWFya2Rvd259CiAgXHVzZXBhY2thZ2VbdXRmOF17aW5wdXRlbmN9Ci0tLQogIApgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGRwaSA9IDMwMCwgY2FjaGUgPSBGQUxTRSkKYGBgCgpgYGB7ciwgZWNobyA9IEZBTFNFLGhpZGU9VFJVRSwgbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQpkZXZ0b29sczo6bG9hZF9hbGwoIi4iKQpkaXIuY3JlYXRlKCJyZXN1bHQiLHNob3dXYXJuaW5ncyA9IEZBTFNFKQpsaWJyYXJ5KEJpb2NTdHlsZSkKYGBgCgojIEludHJvZHVjdGlvbgoKVGhpcyBkb2N1bWVudCBwcm92aWRlcyBhbiBpbnRyb2R1Y3Rpb24gb2YgdGhlIFIvQmlvY29uZGN1dG9yICBgciBCaW9jU3R5bGU6OkJpb2Nwa2coIkVMTUVSIilgIHBhY2thZ2UsIHdoaWNoIGlzIGRlc2lnbmVkIAp0byBjb21iaW5lIEROQSBtZXRoeWxhdGlvbiBhbmQgZ2VuZSBleHByZXNzaW9uIGRhdGEgZnJvbSBodW1hbiB0aXNzdWVzIHRvIGluZmVyIAptdWx0aS1sZXZlbCBjaXMtcmVndWxhdG9yeSBuZXR3b3Jrcy4gYHIgQmlvY1N0eWxlOjpCaW9jcGtnKCJFTE1FUiIpYCB1c2VzIEROQSBtZXRoeWxhdGlvbiB0byAKaWRlbnRpZnkgZW5oYW5jZXJzLCBhbmQgY29ycmVsYXRlcyBlbmhhbmNlciBzdGF0ZSB3aXRoIGV4cHJlc3Npb24gb2YgbmVhcmJ5IGdlbmVzIAp0byBpZGVudGlmeSBvbmUgb3IgbW9yZSB0cmFuc2NyaXB0aW9uYWwgdGFyZ2V0cy4gVHJhbnNjcmlwdGlvbiBmYWN0b3IgKFRGKSBiaW5kaW5nIApzaXRlIGFuYWx5c2lzIG9mIGVuaGFuY2VycyBpcyBjb3VwbGVkIHdpdGggZXhwcmVzc2lvbiBhbmFseXNpcyBvZiBhbGwgVEZzIHRvIAppbmZlciB1cHN0cmVhbSByZWd1bGF0b3JzLiBUaGlzIHBhY2thZ2UgY2FuIGJlIGVhc2lseSBhcHBsaWVkIHRvIFRDR0EgcHVibGljIAphdmFpbGFibGUgY2FuY2VyIGRhdGEgc2V0cyBhbmQgY3VzdG9tIEROQSBtZXRoeWxhdGlvbiBhbmQgZ2VuZSBleHByZXNzaW9uIGRhdGEgc2V0cy4KCkVMTUVSIGFuYWx5c2VzIGhhdmUgNSBtYWluIHN0ZXBzOiAKCjEuIElkZW50aWZ5IGRpc3RhbCBwcm9iZXMgb24gSE00NTBLLgoyLiBJZGVudGlmeSBkaXN0YWwgZW5oYW5jZXIgcHJvYmVzIHdpdGggc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgRE5BIG1ldGh5bGF0aW9uIGxldmVsCmluIGNvbnRyb2wgZ3JvdXAgYW5kIGV4cGVyaW1lbnQgZ3JvdXAuCjMuIElkZW50aWZ5IHB1dGF0aXZlIHRhcmdldCBnZW5lcyBmb3IgZGlmZmVyZW50aWFsbHkgbWV0aHlsYXRlZCBkaXN0YWwgZW5oYW5jZXIgcHJvYmVzLgo0LiBJZGVudGlmeSBlbnJpY2hlZCBtb3RpZnMgZm9yIHRoZSBkaXN0YWwgZW5oYW5jZXIgcHJvYmVzIHdoaWNoIGFyZSBzaWduaWZpY2FudGx5IApkaWZmZXJlbnRpYWxseSBtZXRoeWxhdGVkIGFuZCBsaW5rZWQgdG8gcHV0YXRpdmUgdGFyZ2V0IGdlbmUuCjUuIElkZW50aWZ5IHJlZ3VsYXRvcnkgVEZzIHdob3NlIGV4cHJlc3Npb24gYXNzb2NpYXRlIHdpdGggRE5BIG1ldGh5bGF0aW9uIGF0IG1vdGlmcy4KCiMjIFBhY2thZ2Ugd29ya2Zsb3cKClRoZSBwYWNrYWdlIHdvcmtmbG93IGlzIHNob3dlZCBpbiB0aGUgZmlndXJlIGJlbG93OgoKIVtFTE1FUiB3b3JrZmxvdzogRUxNRVIgcmVjZWl2ZXMgYXMgaW5wdXQgYSBETkEgbWV0aHlsYXRpb24gb2JqZWN0LCBhIGdlbmUgZXhwcmVzc2lvbiBvYmplY3QgKGJvdGggY2FuIGJlIGVpdGhlciBhIG1hdHJpeCBvciBhIFN1bW1hcml6ZWRFeHBlcmltZW50IG9iamVjdCkgYW5kIGEgR2Vub21pYyBSYW5nZXMgKEdSYW5nZXMpIG9iamVjdCB3aXRoIGRpc3RhbCBwcm9iZXMgdG8gYmUgdXNlZCBhcyBmaWx0ZXIgd2hpY2ggY2FuIGJlIHJldHJpZXZlZCB1c2luZyB0aGUgYGdldC5mZWF0dXJlLnByb2JlYCBmdW5jdGlvbi4gVGhlIGZ1bmN0aW9uIGNyZWF0ZU1BRSAgd2lsbCBjcmVhdGUgYSBNdWx0aSBBc3NheSBFeHBlcmltZW50IG9iamVjdCBrZWVwaW5nIG9ubHkgc2FtcGxlcyB0aGF0IGhhdmUgYm90aCBETkEgbWV0aHlsYXRpb24gYW5kIGdlbmUgZXhwcmVzc2lvbiBkYXRhLiBHZW5lcyB3aWxsIGJlIG1hcHBlZCB0byBnZW5vbWljIHBvc2l0aW9uIGFuZCBhbm5vdGF0ZWQgdXNpbmcgRU5TRU1CTCBkYXRhYmFzZSwgd2hpbGUgZm9yIHByb2JlcyBpdCB3aWxsIGFkZCBhbm5vdGF0aW9uIGZyb20gKGh0dHA6Ly96d2R6d2QuZ2l0aHViLmlvL0luZmluaXVtQW5ub3RhdGlvbikuIFRoaXMgTUFFIG9iamVjdCB3aWxsIGJlIHVzZWQgYXMgaW5wdXQgdG8gdGhlIG5leHQgYW5hbHlzaXMgZnVuY3Rpb25zLiBGaXJzdCwgaXQgaWRlbnRpZmllcyBkaWZmZXJlbnRpYWxseSBtZXRoeWxhdGVkIHByb2JlcyBmb2xsb3dlZCBieSB0aGUgaWRlbnRpZmljYXRpb24gb2YgdGhlaXIgbmVhcmVzdCBnZW5lcyAoMTAgdXBzdHJlYW0gYW5kIDEwIGRvd25zdHJlYW0pIHRocm91Z2ggdGhlICBgZ2V0LmRpZmYubWV0aGAgYW5kICBgR2V0TmVhckdlbmVzYCBmdW5jdGlvbnMgcmVzcGVjdGl2ZWx5LiBGb3IgZWFjaCBwcm9iZSBpdCB3aWxsIHZlcmlmeSBpZiBhbnkgb2YgdGhlIG5lYXJieSBnZW5lcyB3ZXJlIGFmZmVjdGVkIGJ5IGl0cyBjaGFuZ2UgaW4gdGhlIEROQSBtZXRoeWxhdGlvbiBsZXZlbCBhbmQgYSBsaXN0IG9mICBnZW5lIGFuZCBwcm9iZXMgcGFpcnMgd2lsbCBiZSBvdXRwdXR0ZWQgZnJvbSBgZ2V0LnBhaXJgIGZ1bmN0aW9uLiBGb3IgdGhlIHByb2JlcyBpbiB0aG9zZSBwYWlycywgaXQgd2lsbCBzZWFyY2ggZm9yIGVucmljaGVkIHJlZ3VsYXRvcnkgVHJhbnNjcmlwdGlvbiBGYWN0b3JzIG1vdGlmcyB3aXRoIHRoZSAgYGdldC5lbnJpY2hlZC5tb3RpZmAgZnVuY3Rpb24uIEZpbmFsbHksIHRoZSAgZW5yaWNoZWQgbW90aWZzIHdpbGwgYmUgY29ycmVsYXRlIHdpdGggdGhlIGxldmVsIG9mIHRoZSB0cmFuc2NyaXB0aW9uIGZhY3RvciB0aHJvdWdoIHRoZSBgZ2V0LlRGc2AgZnVuY3Rpb24uIEluIHRoZSBmaWd1cmUgZ3JlZW4gQm94ZXMgcmVwcmVzZW50cyB1c2VyIGlucHV0IGRhdGEsIGJsdWUgYm94ZXMgcmVwcmVzZW50cyBvdXRwdXQgb2JqZWN0LCBvcmFuZ2UgYm94ZXMgcmVwcmVzZW50cyBhdXhpbGlhcnkgcHJlLWNvbXB1dGVkIGRhdGEgYW5kIGdyYXkgYm94ZXMgYXJlIGZ1bmN0aW9ucy4gXSh3b3JrZmxvdy5wbmcpCgojIyBJbnN0YWxsaW5nIGFuZCBsb2FkaW5nIEVMTUVSCgpUbyBpbnN0YWxsIHRoaXMgcGFja2FnZSwgc3RhcnQgUiBhbmQgZW50ZXI6CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpkZXZ0b29sczo6aW5zdGFsbF9naXRodWIocmVwbyA9ICJ0aWFnb2Noc3QvRUxNRVIuZGF0YSIpCmRldnRvb2xzOjppbnN0YWxsX2dpdGh1YihyZXBvID0gInRpYWdvY2hzdC9FTE1FUiIpCmBgYAoKVGhlbiwgdG8gbG9hZCBFTE1FUiBlbnRlcjoKCmBgYHtyLCBmaWcuaGVpZ2h0PTYsZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1UUlVFfQpsaWJyYXJ5KEVMTUVSLCBxdWlldGx5ID0gVFJVRSkKYGBgCgojIyBDaXRpbmcgdGhpcyB3b3JrCgpJZiB5b3UgdXNlZCBFTE1FUiBwYWNrYWdlIG9yIGl0cyByZXN1bHRzLCBwbGVhc2UgY2l0ZToKCiogWWFvLCBMLiwgU2hlbiwgSC4sIExhaXJkLCBQLiBXLiwgRmFybmhhbSwgUC4gSi4sICYgQmVybWFuLCBCLiBQLiAiSW5mZXJyaW5nIHJlZ3VsYXRvcnkgZWxlbWVudCBsYW5kc2NhcGVzIGFuZCB0cmFuc2NyaXB0aW9uIGZhY3RvciBuZXR3b3JrcyBmcm9tIGNhbmNlciBtZXRoeWxvbWVzLiIgR2Vub21lIEJpb2wgMTYgKDIwMTUpOiAxMDUuCiogWWFvLCBMaWppbmcsIEJlbmphbWluIFAuIEJlcm1hbiwgYW5kIFBlZ2d5IEouIEZhcm5oYW0uICJEZW15c3RpZnlpbmcgdGhlIHNlY3JldCBtaXNzaW9uIG9mIGVuaGFuY2VyczogbGlua2luZyBkaXN0YWwgcmVndWxhdG9yeSBlbGVtZW50cyB0byB0YXJnZXQgZ2VuZXMuIiBDcml0aWNhbCByZXZpZXdzIGluIGJpb2NoZW1pc3RyeSBhbmQgbW9sZWN1bGFyIGJpb2xvZ3kgNTAuNiAoMjAxNSk6IDU1MC01NzMuCgpJZiB5b3UgZ2V0IFRDR0EgZGF0YSB1c2luZyBgZ2V0VENHQWAgZnVuY3Rpb24sIHBsZWFzZSBjaXRlIFRDR0FiaW9saW5rcyBwYWNrYWdlOiAKCiogQ29sYXByaWNvIEEsIFNpbHZhIFRDLCBPbHNlbiBDLCBHYXJvZmFubyBMLCBDYXZhIEMsIEdhcm9saW5pIEQsIFNhYmVkb3QgVCwgTWFsdGEgVE0sIFBhZ25vdHRhIFNNLCBDYXN0aWdsaW9uaSBJLCBDZWNjYXJlbGxpIE0sIEJvbnRlbXBpIEcgYW5kIE5vdXNobWVociBILiAiVENHQWJpb2xpbmtzOiBhbiBSL0Jpb2NvbmR1Y3RvciBwYWNrYWdlIGZvciBpbnRlZ3JhdGl2ZSBhbmFseXNpcyBvZiBUQ0dBIGRhdGEuIiBOdWNsZWljIGFjaWRzIHJlc2VhcmNoICgyMDE1KTogZ2t2MTUwNy4KKiAiVENHQSBXb3JrZmxvdzogQW5hbHl6ZSBjYW5jZXIgZ2Vub21pY3MgYW5kIGVwaWdlbm9taWNzIGRhdGEgdXNpbmcgQmlvY29uZHVjdG9yIHBhY2thZ2VzIi4gRjEwMDBSZXNlYXJjaCBbMTAuMTI2ODgvZjEwMDByZXNlYXJjaC44OTIzLjJdKGh0dHA6Ly9keC5kb2kub3JnL2RvaToxMC4xMjY4OC9mMTAwMHJlc2VhcmNoLjg5MjMuMikgW0AxMC4xMjY4OC9mMTAwMHJlc2VhcmNoLjg5MjMuMl0KCgojIERvd25sb2FkIGV4YW1wbGUgZGF0YQoKVGhlIGZvbGxvd2luZyBzdGVwcyBjYW4gYmUgdXNlZCB0byBkb3dubG9hZCB0aGUgZXhhbXBsZSBkYXRhIHNldCBmb3IgYHIgQmlvY1N0eWxlOjpCaW9jcGtnKCJFTE1FUiIpYC4KCmBgYHtyLCBmaWcuaGVpZ2h0PTYsZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1UUlVFfQpkYXRhKGVsbWVyLmRhdGEuZXhhbXBsZSkKZGF0YShMVVNDX21ldGhfcmVmaW5lZCkKZGF0YShMVVNDX1JOQV9yZWZpbmVkKQpsaWJyYXJ5KERUKQpgYGAKCgojIFF1aWNrIHN0YXJ0OiBydW5uaW5nIFRDR0EgZXhhbXBsZQoKYFRDR0EucGlwZWAgaXMgYSBmdW5jdGlvbiBmb3IgZWFzaWx5IGRvd25sb2FkaW5nIFRDR0EgZGF0YSBhbmQgcGVyZm9ybWluZyBhbGwgCnRoZSBhbmFseXNlcyBpbiBFTE1FUi4gRm9yIGlsbHVzdHJhdGlvbiBwdXJwb3NlLCB3ZSBza2lwIHRoZSBkb3dubG9hZGluZyBzdGVwLiAKVGhlIHVzZXIgY2FuIHVzZSB0aGUgYGdldFRDR0FgIGZ1bmN0aW9uIHRvIGRvd25sb2FkIFRDR0EgZGF0YSBvcgp1c2UgYFRDR0EucGlwZWAgYnkgaW5jbHVkaW5nICJkb3dubG9hZCIgaW4gdGhlIGFuYWx5c2lzIG9wdGlvbi4KClRoZSBmb2xsb3dpbmcgY29tbWFuZCB3aWxsIGRvIGRpc3RhbCBETkEgbWV0aHlsYXRpb24gYW5hbHlzaXMgYW5kIHByZWRpY3QgcHV0YXRpdmUKdGFyZ2V0IGdlbmVzLCBtb3RpZiBhbmFseXNpcyBhbmQgaWRlbnRpZnkgcmVndWxhdG9yeSB0cmFuc2NyaXB0aW9uIGZhY3RvcnMuCgpgYGB7ciwgZmlnLmhlaWdodD02LGV2YWw9RkFMU0V9ClRDR0EucGlwZSgiTFVTQyIsCiAgICAgICAgICB3ZCA9ICIuL0VMTUVSLmV4YW1wbGUiLAogICAgICAgICAgY29yZXMgPSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKS8yLAogICAgICAgICAgbW9kZSA9ICJ1bnN1cGVydmlzZWQiCiAgICAgICAgICBwZXJtdS5zaXplID0gMzAwLAogICAgICAgICAgUGUgPSAwLjAxLAogICAgICAgICAgYW5hbHlzaXMgPSBjKCJkaXN0YWwucHJvYmVzIiwiZGlmZk1ldGgiLCJwYWlyIiwibW90aWYiLCJURi5zZWFyY2giKSwKICAgICAgICAgIGRpZmYuZGlyID0gImh5cG8iLAogICAgICAgICAgcm0uY2hyID0gcGFzdGUwKCJjaHIiLGMoIlgiLCJZIikpKQpgYGAKCjxkaXYgY2xhc3M9InBhbmVsIHBhbmVsLWluZm8iPgo8ZGl2IGNsYXNzPSJwYW5lbC1oZWFkaW5nIj5UQ0dBLnBpcGU6IE1vZGUgYXJndW1lbnQ8L2Rpdj4KPGRpdiBjbGFzcz0icGFuZWwtYm9keSI+CgpJbiB0aGlzIG5ldyB2ZXJzaW9uIHdlIGFkZGVkIHRoZSBhcmd1bWVudCBgbW9kZWAgaW4gdGhlIGBUQ0dBLnBpcGVgIGZ1bmN0aW9uLgpUaGlzIHdpbGwgYXV0b21hdGljYWxseSBzZXQgdGhlIGBtaW5TdWJncm91cEZyYWNgIHRvIHRoZSBmb2xsb3dpbmcgdmFsdWVzOgoKTW9kZXMgYXZhaWxhYmxlOiAKCi0gYHVuc3VwZXJ2aXNlZGA6CiAgLSBVc2UgMjAlIG9mIGVhY2ggZ3JvdXAgdG8gaWRlbnRpZnkgZGlmZmVyZW50bHkgbWV0aHlsYXRlZCByZWdpb25zIChgbWluU3ViZ3JvdXBGcmFjYCA9IDAuMiBpbiBgZ2V0LmRpZmYubWV0aGApCiAgLSBVc2UgNDAlIG9mIGFsbCBzYW1wbGVzIHRvIGNyZWF0ZSBVbm1ldGh5dGxhdGVkIChVKSBhbmQgTWV0aHlsYXRlZCAoTSkgZ3JvdXBzIGluIHRoZSBvdGhlciBzdGVwcyAgKHRoZSBsb3dlc3QgcXVpbnRpbGUgb2Ygc2FtcGxlcyBpcyB0aGUgVSBncm91cCBhbmQgdGhlIGhpZ2hlc3QgcXVpbnRpbGUgc2FtcGxlcyBpcyB0aGUgTSBncm91cCkgKGBtaW5TdWJncm91cEZyYWNgID0gMC40IGluIGBnZXQucGFpcnNgIGFuZCBgZ2V0LlRGc2AgZnVuY3Rpb25zKQotIGBzdXBlcnZpc2VkYDoKICAtIFVzZSBhbGwgc2FtcGxlcyBpbiBhbGwgZnVuY3Rpb25zLgoKVGhlIGB1bnN1cGVydmlzZWRgIG1vZGUgc2hvdWxkIGJlIHVzZWQgd2hlbiB3YW50IHRvIGJlIGFibGUgdG8gZGV0ZWN0IGEgc3BlY2lmaWMgKHBvc3NpYmx5IHVua25vd24pIG1vbGVjdWxhciBzdWJ0eXBlIGFtb25nIHR1bW9yOyAKdGhlc2Ugc3VidHlwZXMgb2Z0ZW4gbWFrZSB1cCBvbmx5IGEgbWlub3JpdHkgb2Ygc2FtcGxlcywgYW5kIDIwXCUgd2FzIGNob3NlbiBhcyBhIGxvd2VyIGJvdW5kIGZvciB0aGUgcHVycG9zZXMgb2Ygc3RhdGlzdGljYWwgcG93ZXIuCklmIHlvdSBhcmUgdXNpbmcgcHJlLWRlZmluZWQgZ3JvdXAgbGFiZWxzLCBzdWNoIGFzIHRyZWF0ZWQgcmVwbGljYXRlcyB2cy4gdW50cmVhdGVkIHJlcGxpY2F0ZWQsIHVzZSBgc3VwZXJ2aXNlZGAgbW9kZSAodXNlIGFsbCBzYW1wbGVzKQoKRm9yIG1vcmUgaW5mb3JtdGFpb24gY29udGludWUgcmVhZGluZyB0aGUgdmlnbmV0dGUuCjwvZGl2Pgo8L2Rpdj4KCgojIElucHV0IGRhdGEKCkEgTXVsdGkgQXNzYXkgRXhwZXJpbWVudCBvYmplY3QgaXMgdGhlIGlucHV0IGZvciBhbGwgbWFpbiBmdW5jdGlvbnMgb2YgYHIgQmlvY1N0eWxlOjpCaW9jcGtnKCJFTE1FUiIpYCBhbmQgY2FuIGJlIGdlbmVyYXRlZCBieSBgY3JlYXRlTUFFYCBmdW5jdGlvbi4gCgpUbyBwZXJmb3JtIGByIEJpb2NTdHlsZTo6QmlvY3BrZygiRUxNRVIiKWAgYW5hbHlzZXMsIHRoZSBbTXVsdGkgQXNzYXkgRXhwZXJpbWVudF0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy9odG1sL011bHRpQXNzYXlFeHBlcmltZW50Lmh0bWwpIG5lZWRzOgoKLSBhIEROQSBtZXRoeWxhdGlvbiBtYXRyaXggb3IgU3VtbWFyaXplZEV4cGVyaW1lbnQgb2JqZWN0IGZyb20gSE00NTBLIG9yIEVQSUMgcGxhdGZvcm0gZm9yIG11bHRpcGxlIHNhbXBsZXM7Ci0gYSBnZW5lIGV4cHJlc3Npb24gbWF0cml4IG9yIFN1bW1hcml6ZWRFeHBlcmltZW50IG9iamVjdCBmb3IgdGhlIHNhbWUgc2FtcGxlczsKLSBhIG1hdHJpeCBtYXBwaW5nIEROQSBtZXRoeWxhdGlvbiBzYW1wbGVzIHRvIGdlbmUgZXhwcmVzc2lvbiBzYW1wbGVzIAotIGEgbWF0cml4IHdpdGggc2FtcGxlcyBtZXRhZGF0YSAoaS5lLiBjbGluaWNhbCBkYXRhLCBtb2xlY3VsYXIgIHN1YnR5cGUgaW5mb3JtYXRpb24pLiAKCklmIFRDR0EgZGF0YSBhcmUgdXNlZCwgdGhlIHRoZSBsYXN0IHR3byBtYXRyaWNlcyB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkLgpCYXNlZCBvbiB0aGUgZ2Vub21lIG9mIHJlZmVyZW5jZSBzZWxlY3RlZCwgbWV0YWRhdGEgZm9yIHRoZSBETkEgbWV0aHlsYXRpb24gcHJvYmVzLCBzdWNoIGFzIGdlbm9taWMgY29vcmRpbmF0ZXMsIHdpbGwgYmUgYWRkZWQgZnJvbSAgW1dhbmRpbmcgWmhvdSBhbm5vdGF0aW9uXShodHRwOi8vendkendkLmdpdGh1Yi5pby9JbmZpbml1bUFubm90YXRpb24pW0B6aG91MjAxNmNvbXByZWhlbnNpdmVdOyAKYW5kIG1ldGFkYXRhIGZvciBnZW5lIGFubm90YXRpb24gIHdpbGwgYmUgYWRkZWQgZnJvbSBlbnNlbWJsZSBkYXRhYmFzZSBbQHlhdGVzMjAxNWVuc2VtYmxdIHVzaW5nIFtiaW9tYVJ0XShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9iaW9tYVJ0LykKW0BkdXJpbmNrMjAwOW1hcHBpbmddLgoKCiMjIEROQSBtZXRoeWxhdGlvbiBkYXRhCgpETkEgbWV0aHlsYXRpb24gZGF0YSBmZWVkaW5nIHRvIGByIEJpb2NTdHlsZTo6QmlvY3BrZygiRUxNRVIiKWAgc2hvdWxkIGJlIGEgbWF0cml4IG9mIEROQSBtZXRoeWxhdGlvbgpiZXRhICgkXGJldGEkKSB2YWx1ZSBmb3Igc2FtcGxlcyAoY29sdW1uKSBhbmQgcHJvYmVzIChyb3cpIHByb2Nlc3NlZCBmcm9tIHJvdyBITTQ1MEsgCmFycmF5IGRhdGEuIElmIFRDR0EgZGF0YSBpcyB1c2VkLCBwcm9jZXNzZWQgZGF0YSBmcm9tIEdEQyB3ZWJzaXRlIHdpbGwgYmUgZG93bmxvYWRlZCAgCmFuZCBhdXRvbWF0aWNhbGx5IHRyYW5zZm9ybWVkIHRvIHRoZSBtYXRyaXggYnkgYHIgQmlvY1N0eWxlOjpCaW9jcGtnKCJFTE1FUiIpYC4gVGhlIHByb2Nlc3NlZCBUQ0dBIApETkEgbWV0aHlsYXRpb24gZGF0YSB3ZXJlIGNhbGN1bGF0ZWQgYXMgKE0vKE0rVSkpLCB3aGVyZSBNIHJlcHJlc2VudHMgdGhlIG1ldGh5bGF0ZWQgCmFsbGVsZSBpbnRlbnNpdHkgYW5kIFUgdGhlIHVubWV0aHlsYXRlZCBhbGxlbGUgaW50ZW5zaXR5LiBCZXRhIHZhbHVlcyByYW5nZSBmcm9tIDAgdG8gMSwgCnJlZmxlY3RpbmcgdGhlIGZyYWN0aW9uIG9mIG1ldGh5bGF0ZWQgYWxsZWxlcyBhdCBlYWNoIENwRyBpbiB0aGUgZWFjaCB0dW1vcjsgYmV0YSB2YWx1ZXMgCmNsb3NlIHRvIDAgaW5kaWNhdGVzIGxvdyBsZXZlbHMgb2YgRE5BIG1ldGh5bGF0aW9uIGFuZCBiZXRhIHZhbHVlcyBjbG9zZSB0byAxIAppbmRpY2F0ZXMgaGlnaCBsZXZlbHMgb2YgRE5BIG1ldGh5bGF0aW9uLgoKSWYgdXNlciBoYXZlIHJhdyBITTQ1MEsgZGF0YSwgdGhlc2UgZGF0YSBjYW4gYmUgcHJvY2Vzc2VkIGJ5IGByIEJpb2NTdHlsZTo6QmlvY3BrZygiTWV0aHlsdW1pIilgIApvciBgciBCaW9jU3R5bGU6OkJpb2Nwa2coIm1pbmZpIilgIGdlbmVyYXRpbmcgRE5BIG1ldGh5bGF0aW9uIGJldGEgKCRcYmV0YSQpIHZhbHVlIGZvciBlYWNoIENwRyBzaXRlIAphbmQgbXVsdGlwbGUgc2FtcGxlcy4gVGhlIGBnZXRCZXRhYCBmdW5jdGlvbiBpbiBgciBCaW9jU3R5bGU6OkJpb2Nwa2coIm1pbmZpIilgIGNhbiBiZSB1c2VkIHRvIGdlbmVyYXRlIGEgbWF0cml4IApvZiBETkEgbWV0aHlsYXRpb24gYmV0YSAoJFxiZXRhJCkgdmFsdWUgdG8gZmVlZCBpbiBgciBCaW9jU3R5bGU6OkJpb2Nwa2coIkVMTUVSIilgLiBBbmQgd2UgcmVjb21tZW5kIHRvIApzYXZlIHRoaXMgbWF0cml4IGFzIGBtZXRoLnJkYWAgc2luY2UgIGBjcmVhdGVNQUVgIApjYW4gcmVhZCBpbiBmaWxlcyBieSBzcGVjaWZ5aW5nIHRoZWlyIHBhdGggd2hpY2ggd2lsbCBoZWxwIHRvIHJlZHVjZSBtZW1vcnkgdXNhZ2UuCgpgYGB7cn0KIyBFeGFtcGxlIG9mIEROQSBtZXRoeWxhdGlvbiBkYXRhIGlucHV0CmRhdGF0YWJsZShNZXRoWzE6MTAsIDE6MTBdLCAKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHNjcm9sbFggPSBUUlVFLCBrZXlzID0gVFJVRSwgcGFnZUxlbmd0aCA9IDUpLCAKICAgICAgICAgIHJvd25hbWVzID0gVFJVRSkKYGBgCgojIyBHZW5lIGV4cHJlc3Npb24gZGF0YQoKR2VuZSBleHByZXNpb24gZGF0YSBmZWVkaW5nIHRvIGByIEJpb2NTdHlsZTo6QmlvY3BrZygiRUxNRVIiKWAgc2hvdWxkIGJlIGEgbWF0cml4IG9mIGdlbmUgZXhwcmVzc2lvbgp2YWx1ZXMgZm9yIHNhbXBsZXMgKGNvbHVtbikgYW5kIGdlbmVzIChyb3cpLiBHZW5lIGV4cHJlc3Npb24gdmFsdWUgY2FuIGJlIGdlbmVyYXRlZApmcm9tIGRpZmZlcmVudCBwbGF0Zm9ybXM6IGFycmF5IG9yIFJOQS1zZXEuIFRoZSByb3cgZGF0YSBzaG91bGQgYmUgcHJvY2Vzc2VkIGJ5IG90aGVyCnNvZnR3YXJlIHRvIGdldCBnZW5lIG9yIHRyYW5zY3JpcHQgbGV2ZWwgZ2VuZSBleHByZXNzaW9uIGNhbGxzIHN1Y2ggYXMgbWFwcGluZyBieSAKW3RvcGhhdF0oaHR0cHM6Ly9jY2Iuamh1LmVkdS9zb2Z0d2FyZS90b3BoYXQvaW5kZXguc2h0bWwpLCAKY2FsbGluZyBleHByZXNzaW9uIHZhbHVlIGJ5IFtjdWZmbGlua10oaHR0cHM6Ly9naXRodWIuY29tL2NvbGUtdHJhcG5lbGwtbGFiL2N1ZmZsaW5rcyksIApbUlNFTV0oaHR0cHM6Ly9naXRodWIuY29tL2Rld2V5bGFiL1JTRU0pIG9yIApbR2Vub21lU3R1ZGlvXShodHRwOi8vd3d3LmlsbHVtaW5hLmNvbS90ZWNobmlxdWVzL21pY3JvYXJyYXlzL2FycmF5LWRhdGEtYW5hbHlzaXMtZXhwZXJpbWVudGFsLWRlc2lnbi9nZW5vbWVzdHVkaW8uaHRtbCkgZm9yIGV4cHJlc3Npb24gYXJyYXkuIApJdCBpcyByZWNvbW1lbmRlZCB0byBub3JtYWxpemUgZXhwcmVzc2lvbiBkYXRhIG1ha2luZyBnZW5lIGV4cHJlc3Npb24gCmNvbXBhcmFibGUgYWNyb3NzIHNhbXBsZXMgc3VjaCBhcyBxdWFudGlsZSBub3JtYWxpemF0aW9uLiBVc2VyIGNhbiByZWZlciBUQ0dBIFJOQS1zZXEKYW5hbHlzaXMgcGlwZWxpbmUgdG8gZG8gZ2VuZXJhdGUgY29tcGFyYWJsZSBnZW5lIGV4cHJlc3Npb24gZGF0YS4gVGhlbiB0cmFuc2Zvcm0gdGhlIApnZW5lIGV4cHJlc3Npb24gdmFsdWVzIGZyb20gZWFjaCBzYW1wbGUgdG8gdGhlIG1hdHJpeCBmb3IgZmVlZGluZyBpbnRvIGByIEJpb2NTdHlsZTo6QmlvY3BrZygiRUxNRVIiKWAuCklmIHVzZXJzIHdhbnQgdG8gdXNlIFRDR0EgZGF0YSwgYHIgQmlvY1N0eWxlOjpCaW9jcGtnKCJFTE1FUiIpYCBoYXMgZnVuY3Rpb25zIHRvIGRvd25sb2FkIHRoZSAKUk5BLVNlcSBRdWFudGlmaWNhdGlvbiBkYXRhKEhUU2VxLUZQS00tVVEpICBmcm9tIEdEQyB3ZWJzaXRlIGFuZCB0cmFuc2Zvcm0gdGhlIGRhdGEgdG8gdGhlIG1hdHJpeCBmb3IgZmVlZGluZyAKaW50byBgciBCaW9jU3R5bGU6OkJpb2Nwa2coIkVMTUVSIilgLiBJdCBpcyByZWNvbW1lbmRlZCB0byBzYXZlIHRoaXMgbWF0cml4IGFzIGBSTkEucmRhYCBzaW5jZSBgY3JlYXRlTUFFYCAKY2FuIHJlYWQgaW4gZmlsZXMgYnkgc3BlY2lmeWluZyB0aGUgcGF0aCBvZiBmaWxlcyB3aGljaCB3aWxsIGhlbHAgdG8gcmVkdWNlIG1lbW9yeSB1c2FnZS4KCmBgYHtyfQojIEV4YW1wbGUgb2YgR2VuZSBleHByZXNzaW9uIGRhdGEgaW5wdXQKZGF0YXRhYmxlKEdlbmVFeHBbMToxMCwgMToyXSwgCiAgICAgICAgICBvcHRpb25zID0gbGlzdChzY3JvbGxYID0gVFJVRSwga2V5cyA9IFRSVUUsIHBhZ2VMZW5ndGggPSA1KSwgCiAgICAgICAgICByb3duYW1lcyA9IFRSVUUpCmBgYAoKCiMjIFNhbXBsZSBpbmZvcm1hdGlvbgoKU2FtcGxlIGluZm9ybWF0aW9uIHNob3VsZCBiZSBzdG9yZWQgYXMgYSBkYXRhLmZyYW1lIG9iamVjdCBjb250YWluaW5nIHNhbXBsZSBJRCwgCmdyb3VwIGxhYmVscyAoY29udHJvbCBhbmQgZXhwZXJpbWVudCkuIFNhbXBsZSBJRCBhbmQgZ3JvdXBzIGxhYmVscyBhcmUgcmVxdWlyZWQuCk90aGVyIGluZm9ybWF0aW9uIGZvciBlYWNoIHNhbXBsZSBjYW4gYmUgYWRkZWQgdG8gdGhpcyBkYXRhLmZyYW1lIG9iamVjdC4KV2hlbiBUQ0dBIGRhdGEgd2VyZSB1c2VkLCBzYW1wbGVzIGluZm9ybWF0aW9uIHdpbGwgYmUgYXV0b21hdGljYWxseSBnZW5lcmF0ZWQgYnkgCmBjcmVhdGVNQUVgICBmdW5jdGlvbiBieSBzcGVjaWZ5aW5nIG9wdGlvbiBgVENHQT1UUlVFYC4gQSBjb2x1bW5zIG5hbWUgYFROYCB3aWxsCmNyZWF0ZSB0aGUgZ3JvdXBzIFR1bW9yIGFuZCBOb3JtYWwgdXNpbmcgdGhlIGZvbGxvd2luZyBzYW1wbGVzIHRvIGVhY2ggZ3JvdXA6CgpUdW1vciBzYW1wbGVzIGFyZTogICAKCiAgKiAgIFByaW1hcnkgc29saWQgVHVtb3IKICAqICAgUmVjdXJyZW50IFNvbGlkIFR1bW9yCiAgKiAgIFByaW1hcnkgQmxvb2QgRGVyaXZlZCBDYW5jZXIgLSBQZXJpcGhlcmFsIEJsb29kCiAgKiAgIFJlY3VycmVudCBCbG9vZCBEZXJpdmVkIENhbmNlciAtIEJvbmUgTWFycm93CiAgKiAgIEFkZGl0aW9uYWwgLSBOZXcgUHJpbWFyeQogICogICBNZXRhc3RhdGljCiAgKiAgIEFkZGl0aW9uYWwgTWV0YXN0YXRpYwogICogICBIdW1hbiBUdW1vciBPcmlnaW5hbCBDZWxscwogICogICBQcmltYXJ5IEJsb29kIERlcml2ZWQgQ2FuY2VyIC0gQm9uZSBNYXJyb3cKICAKTm9ybWFsIHNhbXBsZXM6CgogICogQmxvb2QgRGVyaXZlZCBOb3JtYWwKICAqIFNvbGlkIFRpc3N1ZSBOb3JtYWwKICAqIEJ1Y2NhbCBDZWxsIE5vcm1hbAogICogRUJWIEltbW9ydGFsaXplZCBOb3JtYWwKICAqIEJvbmUgTWFycm93IE5vcm1hbAoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoTXVsdGlBc3NheUV4cGVyaW1lbnQpCmRhdGEgPC0gY3JlYXRlTUFFKGV4cCA9IEdlbmVFeHAsIAogICAgICAgICAgICAgICAgICBtZXQgPSBNZXRoLAogICAgICAgICAgICAgICAgICBtZXQucGxhdGZvcm0gPSAiNDUwSyIsCiAgICAgICAgICAgICAgICAgIGdlbm9tZSA9ICJoZzE5IiwKICAgICAgICAgICAgICAgICAgc2F2ZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICBUQ0dBID0gVFJVRSkKZGF0YQphcy5kYXRhLmZyYW1lKGNvbERhdGEoZGF0YSlbLGMoInBhdGllbnQiLCJkZWZpbml0aW9uIiwiVE4iKV0pCgojIEFkZGluZyBzYW1wbGUgaW5mb3JtYXRpb24gZm9yIG5vbiBUQ0dBIHNhbXBsZXMKIyBZb3Ugc2hvdWxkIGhhdmUgdHdvIG9iamVjdHMgd2l0aCBvbmUgZm9yIEROQSBtZXRoeWxhdGlvbiBhbmQgCiMgb25lIGZvciBnZW5lIGV4cHJlc3Npb24uIFRoZXkgc2hvdWxkIGhhdmUgdGhlIHNhbWUgbnVtYmVyIG9mIHNhbXBsZXMgYW5kIHRoZSBuYW1lcyBvZiB0aGUgCiMgc2FtcGxlIGluIHRoZSBnZW5lIGV4cHJlc3Npb24gb2JqZWN0IGFuZCBpbiBodGUgRE5BIG1ldGh5bGF0aW9uIG1hdHJpeCAKIyBzaG91bGQgYmUgdGhlIHNhbWUKbm90LnRjZ2EuZXhwIDwtIEdlbmVFeHAgIyAyMzQgc2FtcGxlcwpjb2xuYW1lcyhub3QudGNnYS5leHApIDwtIHN1YnN0cihjb2xuYW1lcyhub3QudGNnYS5leHApLDEsMTUpCm5vdC50Y2dhLm1ldCA8LSBNZXRoICMgMjY4IHNhbXBsZXMKY29sbmFtZXMobm90LnRjZ2EubWV0KSA8LSBzdWJzdHIoY29sbmFtZXMobm90LnRjZ2EubWV0KSwxLDE1KQojIE51bWJlciBvZiBzYW1wbGVzIGluIGJvdGggb2JqZWN0cyAoMjM0KQp0YWJsZShjb2xuYW1lcyhub3QudGNnYS5tZXQpICVpbiUgY29sbmFtZXMobm90LnRjZ2EuZXhwKSkgCgojIE91ciBzYW1wbGUgaW5mb3JtYXRpb24gbXVzdCBoYXZlIGFzIHJvdyBuYW1lcyB0aGUgc2FtcGxlcyBpbmZvcm1hdGlvbgpwaGVub3R5cGUuZGF0YSA8LSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IGNvbG5hbWVzKG5vdC50Y2dhLmV4cCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZXMgPSBjb2xuYW1lcyhub3QudGNnYS5leHApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGMocmVwKCJncm91cDEiLCBuY29sKEdlbmVFeHApLzIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoImdyb3VwMiIsIG5jb2woR2VuZUV4cCkvMikpKQoKZGF0YS5oZzE5IDwtIGNyZWF0ZU1BRShleHAgPSBub3QudGNnYS5leHAsIAogICAgICAgICAgICAgICAgICAgICAgIG1ldCA9ICBub3QudGNnYS5tZXQsIAogICAgICAgICAgICAgICAgICAgICAgIFRDR0EgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgbWV0LnBsYXRmb3JtID0gIjQ1MEsiLAogICAgICAgICAgICAgICAgICAgICAgIGdlbm9tZSA9ICJoZzE5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IHBoZW5vdHlwZS5kYXRhKQpkYXRhLmhnMTkKCiMgVGhlIHNhbXBsZXMgdGhhdCBkb2VzIG5vdCBoYXZlIGRhdGEgZm9yIGJvdGggRE5BIG1ldGh5bGF0aW9uIGFuZCBHZW5lIGV4cHJzc2lvbiB3aWxsIGJlIHJlbW92ZWQgZXZlbiBmb3IgdGhlIHBoZW5vdHlwZSBkYXRhCnBoZW5vdHlwZS5kYXRhIDwtIGRhdGEuZnJhbWUocm93Lm5hbWVzID0gY29sbmFtZXMobm90LnRjZ2EubWV0KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlcyA9IGNvbG5hbWVzKG5vdC50Y2dhLm1ldCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYyhyZXAoImdyb3VwMSIsIG5jb2woTWV0aCkvNCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgiZ3JvdXAyIiwgbmNvbChNZXRoKS80KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJncm91cDMiLCBuY29sKE1ldGgpLzQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoImdyb3VwNCIsIG5jb2woTWV0aCkvNCkpKQoKZGF0YS5oZzM4IDwtIGNyZWF0ZU1BRShleHAgPSBub3QudGNnYS5leHAsIAogICAgICAgICAgICAgICAgICAgICAgIG1ldCA9ICBub3QudGNnYS5tZXQsIAogICAgICAgICAgICAgICAgICAgICAgIFRDR0EgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgc2F2ZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIG1ldC5wbGF0Zm9ybSA9ICI0NTBLIiwKICAgICAgICAgICAgICAgICAgICAgICBnZW5vbWUgPSAiaGczOCIsIAogICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBwaGVub3R5cGUuZGF0YSkKZGF0YS5oZzM4CmFzLmRhdGEuZnJhbWUoY29sRGF0YShkYXRhLmhnMzgpWzE6MjAsXSkKYGBgCgojIyBQcm9iZSBpbmZvcm1hdGlvbgoKUHJvYmUgaW5mb3JtYXRpb24gaXMgc3RvcmVkIGFzIGEgR1JhbmdlcyBvYmplY3QgY29udGFpbmluZyB0aGUgY29vcmRpbmF0ZXMgCm9mIGVhY2ggcHJvYmUgb24gdGhlIEROQSBtZXRoeWxhdGlvbiBhcnJheSBhbmQgbmFtZXMgb2YgZWFjaCBwcm9iZS4gClRoZSBkZWZhdWx0IHByb2JlIGluZm9ybWF0aW9uIGlzIGZldGNoaW5nIGZyb20gIFtXYW5kaW5nIFpob3UgYW5ub3RhdGlvbl0oaHR0cDovL3p3ZHp3ZC5naXRodWIuaW8vSW5maW5pdW1Bbm5vdGF0aW9uKVtAemhvdTIwMTZjb21wcmVoZW5zaXZlXQoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoU3VtbWFyaXplZEV4cGVyaW1lbnQsIHF1aWV0bHkgPSBUUlVFKQpyb3dSYW5nZXMoZ2V0TWV0KGRhdGEpKVsxOjMsMTo4XQpgYGAKCiMjIEdlbmUgaW5mb3JtYXRpb24KCkdlbmUgaW5mb3JtYXRpb24gaXMgc3RvcmVkIGFzIGEgR1JhbmdlcyBvYmplY3QgY29udGFpbmluZyBjb29yZGluYXRlcyBvZiAKZWFjaCBnZW5lLCBnZW5lIGlkLCBnZW5lIHN5bWJvbCBhbmQgZ2VuZSBpc29mb3JtIGlkLiBUaGUgZGVmYXVsdCBnZW5lIGluZm9ybWF0aW9uIAppcyB0aGUgZW5zZW1ibCBnZW5lIGFubm90YXRpb24gZmV0Y2hlZCBmcm9tIGByIEJpb2NTdHlsZTo6QmlvY3BrZygiYmlvbWFSdCIpYCBieSBgciBCaW9jU3R5bGU6OkJpb2Nwa2coIkVMTUVSIilgIApmdW5jdGlvbi4KCmBgYHtyfQpyb3dSYW5nZXMoZ2V0RXhwKGRhdGEpKQpgYGAKCiMjICBNdWx0aSBBc3NheSBFeHBlcmltZW50IG9iamVjdCAKCkEgTXVsdGkgQXNzYXkgRXhwZXJpbWVudCBvYmplY3QgZnJvbSB0aGUgYHIgQmlvY1N0eWxlOjpCaW9jcGtnKCJNdWx0aUFzc2F5RXhwZXJpbWVudCIpYCAKcGFja2FnZSBpcyB0aGUgaW5wdXQgZm9yIG11bHRpcGxlIG1haW4gZnVuY3Rpb25zIG9mIGByIEJpb2NTdHlsZTo6QmlvY3BrZygiRUxNRVIiKWAuIApJdCBjb250YWlucyB0aGUgYWJvdmUgY29tcG9uZW50cyBhbmQgbWFraW5nIGEgTXVsdGkgQXNzYXkgRXhwZXJpbWVudCBvYmplY3QgYnkgYGNyZWF0ZU1BRWAgZnVuY3Rpb24gd2lsbCBrZWVwIGVhY2gKY29tcG9uZW50IGNvbnNpc3RlbnQgd2l0aCBlYWNoIG90aGVyLiBGb3IgZXhhbXBsZSwgYWx0aG91Z3RoIEROQSBtZXRoeWxhdGlvbiBhbmQgZ2VuZSAKZXhwcmVzc2lvbiBtYXRyaXhlcyBoYXZlIGRpZmZlcmVudCByb3dzIChwcm9iZSBmb3IgRE5BIG1ldGh5bGF0aW9uIGFuZCBnZW5lIGlkIGZvciBnZW5lCmV4cHJlc3Npb24pLCB0aGUgY29sdW1uIChzYW1wbGVzKSBvcmRlciBzaG91bGQgYmUgc2FtZSBpbiB0aGUgdHdvIG1hdHJpeGVzLiBUaGUgYGNyZWF0ZU1BRWAKZnVuY3Rpb24gd2lsbCBrZWVwIHRoZW0gY29uc2lzdGVudCB3aGVuIGl0IGdlbmVyYXRlcyB0aGUgIE11bHRpIEFzc2F5IEV4cGVyaW1lbnQgb2JqZWN0LgoKCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpkYXRhIDwtIGNyZWF0ZU1BRShleHAgPSBHZW5lRXhwLCAKICAgICAgICAgICAgICAgICAgbWV0ID0gTWV0aCwKICAgICAgICAgICAgICAgICAgZ2Vub21lID0gImhnMTkiLAogICAgICAgICAgICAgICAgICBzYXZlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgIG1ldC5wbGF0Zm9ybSA9ICI0NTBLIiwKICAgICAgICAgICAgICAgICAgVENHQSA9IFRSVUUpCgojIEZvciBUR0NBIGRhdGEgMS0xMiByZXByZXNlbnRzIHRoZSBwYXRpZW50IGFuZCAxLTE1IHJlcHJlc2VudHMgdGhlIHNhbXBsZSBJRCAoaS5lLiBwcmltYXJ5IHNvbGlkIHR1bW9yIHNhbXBsZXMgKQphbGwoc3Vic3RyKGNvbG5hbWVzKGdldEV4cChkYXRhKSksMSwxNSkgPT0gc3Vic3RyKGNvbG5hbWVzKGdldE1ldChkYXRhKSksMSwxNSkpCgojIFNlZSBzYW1wbGUgaW5mb3JtYXRpb24gZm9yIGRhdGEKYXMuZGF0YS5mcmFtZShjb2xEYXRhKGRhdGEpKQogICAgICAgICAgCiMgU2VlIHNhbXBsZSBuYW1lcyBmb3IgZWFjaCBleHBlcmltZW50CmFzLmRhdGEuZnJhbWUoc2FtcGxlTWFwKGRhdGEpKQpgYGAKCllvdSBjYW4gYWxzbyB1c2UgeW91ciBvd24gZGF0YSBhbmQgYW5ub3RhdGlvbnMgdG8gY3JlYXRlICBNdWx0aSBBc3NheSBFeHBlcmltZW50IG9iamVjdC4gCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KIyBOT04gVENHQSBleGFtcGxlOiBtYXRyaWNlcyBoYXMgZGlmZmV0cmVudCBjb2x1bW4gbmFtZXMKZ2VuZS5leHAgPC0gRGF0YUZyYW1lKHNhbXBsZTEgPSBjKCJFTlNHMDAwMDAxNDE1MTAiPTIuMywiRU5TRzAwMDAwMTcxODYyIj01LjQpLAogICAgICAgICAgICAgICAgICAgICAgc2FtcGxlMiA9IGMoIkVOU0cwMDAwMDE0MTUxMCI9MS42LCJFTlNHMDAwMDAxNzE4NjIiPTIuMykpCmRuYS5tZXQgPC0gRGF0YUZyYW1lKHNhbXBsZTEgPSBjKCJjZzE0MzI0MjAwIj0wLjUsImNnMjM4Njc0OTQiPTAuMSksCiAgICAgICAgICAgICAgICAgICAgIHNhbXBsZTIgPSAgYygiY2cxNDMyNDIwMCI9MC4zLCJjZzIzODY3NDk0Ij0wLjkpKQpzYW1wbGUuaW5mbyA8LSBEYXRhRnJhbWUoc2FtcGxlLnR5cGUgPSBjKCJOb3JtYWwiLCAiVHVtb3IiKSkKcm93bmFtZXMoc2FtcGxlLmluZm8pIDwtIGNvbG5hbWVzKGdlbmUuZXhwKQoKbWFlIDwtIGNyZWF0ZU1BRShleHAgPSBnZW5lLmV4cCwKICAgICAgICAgICAgICAgICBtZXQgPSBkbmEubWV0LAogICAgICAgICAgICAgICAgIHNhdmUgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBtZXQucGxhdGZvcm0gPSAiNDUwSyIsCiAgICAgICAgICAgICAgICAgY29sRGF0YSA9IHNhbXBsZS5pbmZvLCAKICAgICAgICAgICAgICAgICBnZW5vbWUgPSAiaGczOCIpIAoKIyBOT04gVENHQSBleGFtcGxlOiBtYXRyaWNlcyBoYXMgZGlmZmV0cmVudCBjb2x1bW4gbmFtZXMKcm93bmFtZXMoc2FtcGxlLmluZm8pIDwtIGMoInNhbXBsZTEiLCJzYW1wbGUyIikKCnNhbXBsZU1hcCA8LSBEYXRhRnJhbWUocHJpbWFyeSA9IGMoInNhbXBsZTEiLCJzYW1wbGUxIiwic2FtcGxlMiIsInNhbXBsZTIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZSA9IGMoInNhbXBsZTEuZXhwIiwic2FtcGxlMS5tZXQiLCJzYW1wbGUyLmV4cCIsInNhbXBsZTIubWV0IikpCgptYWUgPC0gY3JlYXRlTUFFKGV4cCA9IGdlbmUuZXhwLCAKICAgICAgICAgICAgICAgICBtZXQgPSBkbmEubWV0LCAKICAgICAgICAgICAgICAgICBzYW1wbGVNYXAgPSBzYW1wbGVNYXAsIAogICAgICAgICAgICAgICAgIGNvbERhdGEgPSBzYW1wbGUuaW5mbywgCiAgICAgICAgICAgICAgICAgc2F2ZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgIG1ldC5wbGF0Zm9ybSA9ICI0NTBLIiwKICAgICAgICAgICAgICAgICBnZW5vbWUgPSAiaGczOCIpIApgYGAKCgojIERvd25sb2FkaW5nIFRDR0EgZGF0YQoKVGhlIGZ1bmN0aW9uIGBnZXRUQ0dBYCB1c2VzIFtUQ0dBYmlvbGlua3NdKGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL1RDR0FiaW9saW5rcy8pCnBhY2thZ2UgW0Bjb2xhcHJpY28yMDE1dGNnYWJpb2xpbmtzXSB0byBkb3dubG9hZCBUQ0dBIGRhdGEgZm9yIGFsbCBzYW1wbGVzIApmb3IgYSBnaXZlbiBkaXNlYXNlIChzdWNoIGFzIEJMQ0EsIExHRywgR0JNKS4gSXRzIG1haW4gYXJndW1lbnRzIGFyZSAKdGhlIGBnZW5vbWVgICB0aGF0IGlmIHNldCB0byAiaGcxOSIgaXQgd2lsbCBkb3dubG9hZCBkYXRhIGZyb20gR0RDIGxlZ2FjeSBhcmNoaXZlIGFuZCBpZiBzZXQgCnRvICJoZzM4IiBpdCB3aWxsIGRvd25sb2FkIGRhdGEgZnJvbSB0aGUgR0RDIGhhcm1vbml6ZWQgZGF0YSBwb3J0YWwuCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLGV2YWwgPSBGQUxTRX0KZ2V0VENHQShkaXNlYXNlID0gIkxVU0MiLCAjIFRDR0EgZGlzZWFzZSBhYmJyZXZpYXRpb24gKEJSQ0EsQkxDQSxHQk0sIExHRywgZXRjKQogICAgICAgIGJhc2VkaXIgPSAiREFUQSIsICMgV2hlcmUgZGF0YSB3aWxsIGJlIGRvd25sb2FkZWQKICAgICAgICBnZW5vbWUgID0gImhnMzgiKSAjIEdlbm9tZSBvZiByZWZlbnJlY2UgImhnMzgiIG9yICJoZzE5IgpgYGAKCgpJZiB0aGUgYGdldFRDR0FgIGZ1bmN0aW9uIGNhbGxlZCBiZWZvcmUgd2FzIHN1Y2Nlc3NmdWwgaXQgd2lsbCBjcmVhdGUgdGhlIGZvbGxvd2luZyBvYmplY3RzIGFuZCBmb2xkZXJzOgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLGV2YWwgPSBGQUxTRX0KLS0tIERBVEEvQlJDQS8KICB8LS0tLS0tLS0tLS0gQlJDQV9tZXRoX2hnMzgucmRhIChvYmplY3Qgd2l0aCBETkEgbWV0aHlsYXRpb24pCiAgfC0tLS0tLS0tLS0tIEJSQ0FfUk5BX2hnMzgucmRhIChvYmplY3Qgd2l0aCBnZW5lIGV4cHJlc3Npb24pCiAgfC0tLS0tLS0tLS0tIEJSQ0FfY2xpbmljLnJkYSAgIChvYmplY3Qgd2l0aCBpbmRleGVkIGNsaW5pY2FsIGluZm9ybWF0aW9uKQogIHwtLS0tLS0tLS0tLSBSYXcvIChmb2xkZXI6IGNvbnRhaW5zIEFsbCByYXcgZGF0YSBmcm9tIEdEQykKYGBgCiMgSWxsdXN0cmF0aW9uIG9mIEVMTUVSIGFuYWx5c2lzIHN0ZXBzCgpUaGUgZXhhbXBsZSBkYXRhIHNldCBpcyBhIHN1YnNldCBvZiBjaHJvbW9zb21lIDEgZGF0YSBmcm9tIFRDR0EgTFVTQy4KRUxNRVIgYW5hbHlzaXMgaGF2ZSA1IG1haW4gc3RlcHMgd2hpY2ggYXJlIHNob3duIGJlbG93IGluZGl2aWR1YWxseS4gYFRDR0EucGlwZWAgCmludHJvZHVjZWQgYWJvdmUgaXMgYSBwaXBlbGluZSBjb21iaW5pbmcgYWxsIDUgc3RlcHMgYW5kIHByb2R1Y2luZyBhbGwKcmVzdWx0cyBhbmQgZmlndXJlcy4gCgojIyBTZWxlY3Rpb24gb2YgcHJvYmVzIHdpdGhpbiBiaW9mZWF0dXJlcwoKVGhpcyBzdGVwIGlzIHRvIHNlbGVjdCBITTQ1MEsvRVBJQyBwcm9iZXMsIHdoaWNoIGxvY2F0ZSBmYXIgZnJvbSBUU1MgKGF0IGxlYXN0IDJLYiBhd2F5KSAKIFRoZXNlIHByb2JlcyBhcmUgY2FsbGVkIGRpc3RhbCAgcHJvYmVzLgoKQmUgZGVmYXVsdCwgdGhpcyBjb21wcmVoZW5zaXZlIGxpc3Qgb2YgIFRTUyBhbm5vdGF0ZWQgYnkgRU5TRU1CTCBkYXRhYmFzZSwKd2hpY2ggaXMgcHJvZ3JhbWF0aWNhbGx5IGFjY2Vzc2VkIHVzaW5nIGByIEJpb2NTdHlsZTo6QmlvY3BrZygiYmlvbWFSdCIpYCB0byBnZXQgaXRzIGxhc3QgdmVyc2lvbiwKd2lsbCBiZSB1c2VkIHRvIHNlbGVjdCBkaXN0YWwgcHJvYmVzLiBCdXQgdXNlciBjYW4gdXNlIHRoZWlyIApvd24gVFNTIGFubm90YXRpb24gb3IgYWRkIGZlYXR1cmVzIHN1Y2ggYXMgSDNLMjdhYyBDaElQLXNlcSBpbiBhIGNlcnRhaW4gY2VsbCBsaW5lLCB0byBzZWxlY3QgcHJvYmVzIApvdmVybGFwcGluZyB0aG9zZXMgZmVhdHVyZXMgcmVnaW9ucy4KCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KIyBnZXQgZGlzdGFscHJvYmVzIHRoYXQgYXJlIDJrYiBhd2F5IGZyb20gVFNTIG9uIGNocm9tb3NvbWUgMQpQcm9iZSA8LSBnZXQuZmVhdHVyZS5wcm9iZShnZW5vbWUgPSAiaGcxOSIsIG1ldC5wbGF0Zm9ybSA9ICI0NTBLIiwgcm0uY2hyID0gcGFzdGUwKCJjaHIiLGMoMjoyMiwiWCIsIlkiKSkpCnNhdmUoUHJvYmUsZmlsZSA9ICJyZXN1bHQvcHJvYmVJbmZvX2ZlYXR1cmVfZGlzdGFsLnJkYSIpCmBgYAoKIyMgSWRlbnRpZnlpbmcgZGlmZmVyZW50aWFsbHkgbWV0aHlsYXRlZCBwcm9iZXMKClRoaXMgc3RlcCBpcyB0byBpZGVudGlmeSBETkEgbWV0aHlsYXRpb24gY2hhbmdlcyBhdCBkaXN0YWwgZW5oYW5jZXIgcHJvYmVzIHdoaWNoIGlzCmNhcnJpZWQgb3V0IGJ5IGZ1bmN0aW9uIGBnZXQuZGlmZi5tZXRoYC4gICAgCgojIyMgRGVzY3JpcHRpb24gCgpGb3IgZWFjaCBkaXN0YWwgcHJvYmUsIHRoZSBmdW5jdGlvbiBmaXJzdCByYW5rIHNhbXBsZXMgZnJvbSBncm91cCAxIGFuZCBncm91cCAyIHNhbXBsZXMgCmJ5IHRoZWlyIEROQSBtZXRoeWxhdGlvbiBiZXRhIHZhbHVlcy4gVG8gaWRlbnRpZnkgaHlwb21ldGh5bGF0ZWQgcHJvYmVzLCB0aGUgZnVuY3Rpb24gCmNvbXBhcmVkIHRoZSBsb3dlciBjb250cm9sIHF1aW50aWxlICgyMCUgb2YgY29udHJvbCBzYW1wbGVzIHdpdGggdGhlIGxvd2VzdCBtZXRoeWxhdGlvbikgCnRvIHRoZSBsb3dlciBleHBlcmltZW50IHF1aW50aWxlICgyMCUgb2YgZXhwZXJpbWVudCBzYW1wbGVzIHdpdGggdGhlIGxvd2VzdCBtZXRoeWxhdGlvbiksIAp1c2luZyBhbiB1bnBhaXJlZCBvbmUtdGFpbGVkIHQtdGVzdC4gT25seSB0aGUgbG93ZXIgcXVpbnRpbGVzIHdlcmUgdXNlZCBiZWNhdXNlIHdlIApkaWQgbm90IGV4cGVjdCBhbGwgY2FzZXMgdG8gYmUgZnJvbSBhIHNpbmdsZSBtb2xlY3VsYXIgc3VidHlwZSwgYW5kIHdlIHNvdWdodCB0byAKaWRlbnRpZnkgbWV0aHlsYXRpb24gY2hhbmdlcyB3aXRoaW4gY2FzZXMgZnJvbSB0aGUgc2FtZSBtb2xlY3VsYXIgc3VidHlwZS4gMjAlIChpLmUuIGEgcXVpbnRpbGUpIAp3YXMgcGlja2VkIGFzIGEgY3V0b2ZmIHRvIGluY2x1ZGUgaGlnaCBlbm91Z2ggc2FtcGxlIG51bWJlcnMgdG8geWllbGQgdC10ZXN0IHAtdmFsdWVzIAp0aGF0IGNvdWxkIG92ZXJjb21lIG11bHRpcGxlIGh5cG90aGVzaXMgY29ycmVjdGlvbiwgeWV0IGxvdyBlbm91Z2ggdG8gYmUgYWJsZSB0byAKY2FwdHVyZSBjaGFuZ2VzIGluIGluZGl2aWR1YWwgbW9sZWN1bGFyIHN1YnR5cGVzIG9jY3VycmluZyBpbiAyMCUgb3IgbW9yZSBvZiB0aGUgY2FzZXMuClRoaXMgbnVtYmVyIGNhbiBiZSBzZXQgYXJiaXRyYXJpbHkgYXMgYW4gaW5wdXQgdG8gdGhlIGdldC5kaWZmLm1ldGggZnVuY3Rpb24gaW4gdGhlIApgciBCaW9jU3R5bGU6OkJpb2Nwa2coIkVMTUVSIilgLCBhbmQgc2hvdWxkIGJlIHR1bmVkIGJhc2VkIG9uIHNhbXBsZSBzaXplcyBpbiBpbmRpdmlkdWFsIHN0dWRpZXMuIApUaGUgb25lIHRhaWxlZCB0LXRlc3Qgd2FzIHVzZWQgdG8gcnVsZSBvdXQgdGhlIG51bGwgaHlwb3RoZXNpczogJFxtdV97ZXhwZXJpbWVudH0gXGdlcSBcbXVfe2NvbnRyb2x9JCwgCndoZXJlICRcbXVfe2V4cGVyaW1lbnR9JCBpcyB0aGUgbWVhbiBtZXRoeWxhdGlvbiB3aXRoaW4gdGhlIGxvd2VzdCBleHBlcmltZW50IHF1aW50aWxlIGFuZCAkXG11JGNvbnRyb2wgCmlzIHRoZSBtZWFuIHdpdGhpbiB0aGUgbG93ZXN0IGNvbnRyb2wgcXVpbnRpbGUuIFJhdyBwLXZhbHVlcyB3ZXJlIGFkanVzdGVkIGZvciBtdWx0aXBsZQpoeXBvdGhlc2lzIHRlc3RpbmcgdXNpbmcgdGhlIEJlbmphbWluaS1Ib2NoYmVyZyBtZXRob2QsIGFuZCBwcm9iZXMgd2VyZSBzZWxlY3RlZCAKd2hlbiB0aGV5IGhhZCBhZGp1c3RlZCBwLXZhbHVlIGxlc3MgdGhhbiAwLjAxLiBGb3IgYWRkaXRpb25hbCBzdHJpbmdlbmN5LCBwcm9iZXMgCndlcmUgb25seSBzZWxlY3RlZCBpZiB0aGUgbWV0aHlsYXRpb24gZGlmZmVyZW5jZTogJFxEZWx0YSA9IFxtdV97ZXhwZXJpbWVudH0gLSBcbXVfe2NvbnRyb2x9JCB3YXMgCmdyZWF0ZXIgdGhhbiAwLjMuIFRoZSBzYW1lIG1ldGhvZCB3YXMgdXNlZCB0byBpZGVudGlmeSBoeXBlcm1ldGh5bGF0ZWQgcHJvYmVzLCAKZXhjZXB0IHdlIHVzZWQgdXBwZXIgZXhwZXJpbWVudCBxdWludGlsZSBhbmQgdXBwZXIgY29udHJvbCBxdWludGlsZSwgYW5kIGNob3NlIAp0aGUgb3Bwb3NpdGUgdGFpbCBpbiB0aGUgdC10ZXN0LiAKCklmIGBzYXZlYCBwYXJhbWV0ZXIgb2YgYGdldC5kaWZmLm1ldGhgIGlzIGBUUlVFYCwgdHdvIGN2cyBmaWxlcyB3aWxsIGJlIHNhdmVkLiBJZiBmYWxzZSwKYSBkYXRhIGZyYW1lIHdpdGggdGhlIHNhbWUgY29udGVudCBhcyB0aGUgc2Vjb25kIGZpbGUgbWVudGlvbmVkIGJlbG93IHdpbGwgYmUgcmVwb3J0ZWQuCgpUaGUgZmlyc3QgZmlsZSBjb250YWlucyBhbGwgc3RhdGlzdGljIHJlc3VsdHMgZm9yIGFsbCBwcm9iZXMgd2hpY2ggd2VyZSBmZWQgaW50byB0aGUgCmZ1bmN0aW9uLiBCYXNlZCBvbiB0aGlzIGZpbGUsIHVzZXIgY2FuIGNoYW5nZSBkaWZmZXJlbnQgUCB2YWx1ZSBvciBgc2lnLmRpZmAgY3V0b2ZmIAp0byBzZWxlY3QgdGhlIHNpZ25pZmljYW50IHJlc3VsdHMgd2l0aG91dCByZWRvIHRoZSBhbmFseXNpcy4KClRoZSBzZWNvbmQgZmlsZSBjb250YWlucyBzdGF0aXN0aWMgcmVzdWx0cyBmb3IgdGhlIHByb2JlcyB0aGF0IHBhc3MgdGhlIHNpZ25pZmljYW50CmNyaXRlcmlhIChQIHZhbHVlIGFuZCBzaWcuZGlyKS4KCkJvdGggZmlsZXMgY29udGFpbiBmb3VyIGNvbHVtbnM6IHByb2JlLCBwdmFsdWUsIEV4cGVyaW1lbnRNaW5Db250cm9sLCBhZGp1c3QucC4KCjEuIHByb2JlOiB0aGUgbmFtZSBvZiBwcm9iZXMuCjIuIHB2YWx1ZTogdGhlIHJhdyBQIHZhbHVlIGZyb20gdC10ZXN0LgozLiBFeHBlcmltZW50TWluQ29udHJvbDogIG1ldGh5bGF0aW9uIGRpZmZlcmVuY2UgJFxEZWx0YSQuCjQuIGFkanVzdC5wOiBhZGp1c3RlZCBQIHZhbHVlIGZvciB0LXRlc3QuCgojIyMgQXJndW1lbnRzClRoZSBtYWluIGFyZ3VtZW50cyBvZiB0aGlzIGZ1bmN0aW9uIGFyZToKCnwgQXJndW1lbnQgfCBEZXNjcmlwdGlvbiB8CnwtLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgZGF0YSB8IEEgYG11bHRpQXNzYXlFeHBlcmltZW50YCB3aXRoIEROQSBtZXRoeWxhdGlvbiBhbmQgR2VuZSBFeHByZXNzaW9uIGRhdGEuIFNlZSBgY3JlYXRlTUFFYCBmdW5jdGlvbi4gfAp8IGRpZmYuZGlyIHwgIEEgY2hhcmFjdGVyIGNhbiBiZSAiaHlwbyIgb3IgImh5cGVyIiwgc2hvd2luZyBkaWZmZXJlbnRpYWwgbWV0aHlsYXRpb24gZGlyY3Rpb24uICBJdCBjYW4gYmUgImh5cG8iIHdoaWNoIGlzIG9ubHkgc2VsZWN0aW5nIGh5cG9tZXRoeWxhdGVkIHByb2JlczsgICJoeXBlciIgd2hpY2ggaXMgb25seSBzZWxlY3RpbmcgaHlwZXJtZXRoeWxhdGVkIHByb2JlcyB8CnwgY29yZXMgfCBBIGludGVyZ2VyIHdoaWNoIGRlZmluZXMgdGhlIG51bWJlciBvZiBjb3JlcyB0byBiZSB1c2VkIGluIHBhcmFsbGVsIHByb2Nlc3MuIERlZmF1bHQgaXMgMTogbm8gcGFyYWxsZWwgcHJvY2Vzcy4gfAp8IG1pblN1Ymdyb3VwRnJhYyB8ICBBIG51bWJlciByYW5naW5nIGZyb20gMCB0byAxLHNwZWNpZnlpbmcgdGhlIGZyYWN0aW9uIG9mIGV4dHJlbWUgc2FtcGxlcyBmcm9tIGdyb3VwIDEgYW5kIGdyb3VwIDIgIHRoYXQgYXJlIHVzZWQgdG8gaWRlbnRpZnkgdGhlIGRpZmZlcmVudGlhbCBETkEgbWV0aHlsYXRpb24uICBUaGUgZGVmYXVsdCBpcyAwLjIgYmVjYXVzZSB3ZSB0eXBpY2FsbHkgd2FudCB0byBiZSBhYmxlIHRvIGRldGVjdCBhIHNwZWNpZmljIChwb3NzaWJseSB1bmtub3duKSBtb2xlY3VsYXIgc3VidHlwZSBhbW9uZyB0dW1vcjsgdGhlc2Ugc3VidHlwZXMgb2Z0ZW4gbWFrZSB1cCBvbmx5IGEgbWlub3JpdHkgb2Ygc2FtcGxlcywgYW5kIDIwXCUgd2FzIGNob3NlbiBhcyBhIGxvd2VyIGJvdW5kIGZvciB0aGUgcHVycG9zZXMgb2Ygc3RhdGlzdGljYWwgcG93ZXIuIElmIHlvdSBhcmUgdXNpbmcgcHJlLWRlZmluZWQgZ3JvdXAgbGFiZWxzLCBzdWNoIGFzIHRyZWF0ZWQgcmVwbGljYXRlcyB2cy4gdW50cmVhdGVkIHJlcGxpY2F0ZWQsIHVzZSBhIHZhbHVlIG9mIDEuMCAoKioqU3VwZXJ2aXNlZCoqKiBtb2RlKSB8CnwgcHZhbHVlIHwgQSBudW1iZXIgc3BlY2lmaWVzIHRoZSBzaWduaWZpY2FudCBQIHZhbHVlIChhZGp1c3RlZCBQIHZhbHVlIGJ5IEJIKSBjdXRvZmYgZm9yIHNlbGVjdGluZyBzaWduaWZpY2FudCBoeXBvL2h5cGVyLW1ldGh5bGF0ZWQgcHJvYmVzLiBEZWZhdWx0IGlzIDAuMDEgfAp8IGdyb3VwLmNvbCB8IEEgY29sdW1uIGRlZmluaW5nIHRoZSBncm91cHMgb2YgdGhlIHNhbXBsZS4gWW91IGNhbiB2aWV3IHRoZSBhdmFpbGFibGUgY29sdW1ucyB1c2luZzogYGNvbG5hbWVzKE11bHRpQXNzYXlFeHBlcmltZW50Ojpjb2xEYXRhKGRhdGEpKWAuIHwKfCBncm91cDEgfCBBIGdyb3VwIGZyb20gZ3JvdXAuY29sLiBFTE1FUiB3aWxsIHJ1biBncm91cDEgdnMgZ3JvdXAyLiBUaGF0IG1lYW5zLCBpZiBkaXJlY3Rpb24gaXMgaHlwZXIsIGdldCBwcm9iZXMgaHlwZXJtZXRoeWxhdGVkIGluIGdyb3VwIDEgY29tcGFyZWQgdG8gZ3JvdXAgMi4gfAp8IGdyb3VwMiB8IEEgZ3JvdXAgZnJvbSBncm91cC5jb2wuIEVMTUVSIHdpbGwgcnVuIGdyb3VwMSB2cyBncm91cDIuIFRoYXQgbWVhbnMsIGlmIGRpcmVjdGlvbiBpcyBoeXBlciwgZ2V0IHByb2JlcyBoeXBlcm1ldGh5bGF0ZWQgaW4gZ3JvdXAgMSBjb21wYXJlZCB0byBncm91cCAyLiB8CnwgdGVzdCB8IFN0YXRpc3RpY2FsIHRlc3QgdG8gYmUgdXNlZC4gT3B0aW9uczogdC50ZXN0IChERUZBVUxUKSwgd2lsY294LnRlc3QgfAp8IHNpZy5kaWYgfCBBIG51bWJlciBzcGVjaWZpZXMgdGhlIHNtYWxsZXN0IEROQSBtZXRoeWxhdGlvbiBkaWZmZXJlbmNlIGFzIGEgY3V0b2ZmIGZvciBzZWxlY3Rpbmcgc2lnbmlmaWNhbnQgaHlwby9oeXBlci1tZXRoeWxhdGVkIHByb2Jlcy4gRGVmYXVsdCBpcyAwLjMuIHwKfCBkaXIub3V0IHwgQSBwYXRoIHNwZWNpZnkgdGhlIGRpcmVjdG9yeSBmb3Igb3V0cHV0cy4gRGVmYXVsdCBpcyBpcyBjdXJyZW50IGRpcmVjdG9yeS4gfAp8IHNhdmUgfCBBIGxvZ2ljLiBXaGVuIFRSVUUsIHR3byBnZXRNZXRoZGlmZi5YWC5jc3YgZmlsZXMgd2lsbCBiZSBnZW5lcmF0ZWQgKHNlZSBkZXRhaWwpIHwKCiMjIyBDb2RlIGV4YW1wbGUKYGBge3IsZXZhbD1UUlVFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KE11bHRpQXNzYXlFeHBlcmltZW50KQpkYXRhIDwtIGNyZWF0ZU1BRShleHAgPSBHZW5lRXhwLCAKICAgICAgICAgICAgICAgICAgbWV0ID0gTWV0aCwKICAgICAgICAgICAgICAgICAgc2F2ZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICBtZXQucGxhdGZvcm0gPSAiNDUwSyIsCiAgICAgICAgICAgICAgICAgIGdlbm9tZSA9ICJoZzE5IiwKICAgICAgICAgICAgICAgICAgVENHQSA9IFRSVUUpCmFzLmRhdGEuZnJhbWUoY29sRGF0YShkYXRhKVsxOjUsXSkKCnNpZy5kaWZmIDwtIGdldC5kaWZmLm1ldGgoZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAuY29sID0gImRlZmluaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwMSA9ICAiUHJpbWFyeSBzb2xpZCBUdW1vciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAyID0gIlNvbGlkIFRpc3N1ZSBOb3JtYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgIG1pblN1Ymdyb3VwRnJhYyA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICBzaWcuZGlmID0gMC4zLAogICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmYuZGlyID0gImh5cG8iLCAjIFNlYXJjaCBmb3IgaHlwb21ldGh5bGF0ZWQgcHJvYmVzIGluIGdyb3VwIDEKICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JlcyA9IHBhcmFsbGVsOjpkZXRlY3RDb3JlcygpLzIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGRpci5vdXQgPSJyZXN1bHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsdWUgPSAwLjAxKQoKYXMuZGF0YS5mcmFtZShzaWcuZGlmZikKIyBnZXQuZGlmZi5tZXRoIGF1dG9tYXRpY2FsbHkgc2F2ZSBvdXRwdXQgZmlsZXMuIAojIGdldE1ldGhkaWZmLmh5cG8ucHJvYmVzLmNzdiBjb250YWlucyBzdGF0aXN0aWNzIGZvciBhbGwgdGhlIHByb2Jlcy4KIyBnZXRNZXRoZGlmZi5oeXBvLnByb2Jlcy5zaWduaWZpY2FudC5jc3YgY29udGFpbnMgb25seSB0aGUgc2lnbmlmaWNhbnQgcHJvYmVzIHdoaWNoCiMgaXMgdGhlIHNhbWUgd2l0aCBzaWcuZGlmZgpkaXIocGF0aCA9ICJyZXN1bHQiLCBwYXR0ZXJuID0gImdldE1ldGhkaWZmIikgIApgYGAKCiMjIyBtaW5TdWJncm91cEZyYWM6IERlYWxpbmcgd2l0aCBtb2xlY3VsYXIgc3VieXRwZXMgCgpBcyBzdGF0ZWQgYmVmb3JlIHRoZSBhcmd1bWVudCBgbWluU3ViZ3JvdXBGcmFjYCAoYSBudW1iZXIgcmFuZ2luZyBmcm9tIDAgdG8gMSkgY29udHJvbHMgCnRoZSBudW1iZXIgb2Ygc2FtcGxlcyB0byBiZSB1c2VkIGZyb20gYm90aCBncm91cHMgd2hlbiB5b3UgYXJlIGNvbXBhcmluZyB0aGUgRE5BIG1ldGh5bGF0aW9uIGxldmVsIGF0IGVhY2ggcHJvYmUuCldoZW4gY29tcGFyaW5nIFByaW1hcnkgU29saWQgdHVtb3Igc2FtcGxlcyB2ZXJzdXMgTm9ybWFsIHRpc3N1ZSBzYW1wbGVzIG9ubHkgdGhlIGxvd2VyIHF1aW50aWxlcyB3ZXJlIHVzZWQgYmVjYXVzZSB3ZSAKZGlkIG5vdCBleHBlY3QgYWxsIGNhc2VzIHRvIGJlIGZyb20gYSBzaW5nbGUgbW9sZWN1bGFyIHN1YnR5cGUsIGFuZCB3ZSBzb3VnaHQgdG8gCmlkZW50aWZ5IG1ldGh5bGF0aW9uIGNoYW5nZXMgd2l0aGluIGNhc2VzIGZyb20gdGhlIHNhbWUgbW9sZWN1bGFyIHN1YnR5cGUuCkJ1dCBpZiB5b3UgYXJlIGRlYWxpbmcgYWxyZWFkeSB3aXRoIHN1YnR5cGVzIGl0IGlzIGJldHRlciB0byBzZXQgYG1pblN1Ymdyb3VwRnJhY2AgdG8gMS4KClRoZSBjb2RlIGV4YW1wbGUgYmVsb3cgaGlnaGxpZ2h0IHNvbWUgZGlmZmVyZW50IHByb2JlcyBmb3VuZHMgd2hlbiB1c2luZyAxMDBcJSBvciAyMFwlLgoKYGBge3IgIHJlc3VsdHM9ImhpZGUiLGV2YWw9VFJVRSwgbWVzc2FnZT1GQUxTRX0KIyBXZSB3aWxsIGV2YWx1YXRlIHRoZSBkaWZmZXJlbnQgcHJvYmVzIGZvdW5kIHVzaW5nIGRpZmZlcmVudCBwZXJjZW50YWdlIHZhbHVlcy4KZ3JvdXBDb2wgPC0gInN1YnR5cGVfRXhwcmVzc2lvbi5TdWJ0eXBlIgpncm91cDEgPC0gImNsYXNzaWNhbCIKZ3JvdXAyIDwtICJzZWNyZXRvcnkiCgojIEZvciBlYWNoIHByb2JlIHVzZSBsb3dlciAyMCUgc2FtcGxlcwpzaWcuZGlmZi4yMCA8LSBnZXQuZGlmZi5tZXRoKGRhdGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwLmNvbCA9IGdyb3VwQ29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwMSA9IGdyb3VwMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cDIgPSBncm91cDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluU3ViZ3JvdXBGcmFjID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZy5kaWYgPSAwLjMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZi5kaXIgPSAiaHlwbyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbHVlID0gMC4wMSkKCiMgRm9yIGVhY2ggcHJvYmUgdXNlIGFsbCBzYW1wbGVzCnNpZy5kaWZmLjEwMCA8LSBnZXQuZGlmZi5tZXRoKGRhdGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5jb2wgPSBncm91cENvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAxID0gZ3JvdXAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cDIgPSBncm91cDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pblN1Ymdyb3VwRnJhYyA9IDEuMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnLmRpZiA9IDAuMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlmZi5kaXIgPSAiaHlwbyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsdWUgPSAwLjAxKQpgYGAKYGBge3IgIGV2YWw9VFJVRSwgbWVzc2FnZT1GQUxTRSxmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD00LCB3YXJuaW5nPUZBTFNFfQojIFdoaWNoIHByb2JlcyB3ZXJlIGZvdW5kIHdpdGggMjAlIG9mIHNhbXBsZXMgYW5kIG5vdCB3aXRoIDEwMCUKcHJvYmUgPC0gc2lnLmRpZmYuMjBbd2hpY2goIXNpZy5kaWZmLjIwJHByb2JlICVpbiUgc2lnLmRpZmYuMTAwJHByb2JlKSwicHJvYmUiXQptZXRCb3hQbG90KGRhdGEsZ3JvdXBDb2wsZ3JvdXAxLGdyb3VwMixwcm9iZSA9IHByb2JlWzFdLG1pblN1Ymdyb3VwRnJhYyA9IDAuMiwKICAgICAgICAgICBkaWZmLmRpciA9ICJoeXBvIiwgdGl0bGUgPSAicHJvYmVzIHdlcmUgZm91bmQgd2l0aCAyMCUgb2Ygc2FtcGxlcyBhbmQgbm90IHdpdGggMTAwJSIpCmBgYApgYGB7ciAgZXZhbD1UUlVFLCBtZXNzYWdlPUZBTFNFLGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTQsIHdhcm5pbmc9RkFMU0V9CiMgV2hpY2ggcHJvYmVzIHdlcmUgZm91bmQgd2l0aCAxMDAlIG9mIHNhbXBsZXMgYW5kIG5vdCB3aXRoIDIwJQpwcm9iZSA8LSBzaWcuZGlmZi4xMDBbd2hpY2goIXNpZy5kaWZmLjEwMCRwcm9iZSAlaW4lIHNpZy5kaWZmLjIwJHByb2JlKSwicHJvYmUiXQptZXRCb3hQbG90KGRhdGEsZ3JvdXBDb2wsZ3JvdXAxLGdyb3VwMixwcm9iZSA9IHByb2JlWzFdLCBtaW5TdWJncm91cEZyYWMgPSAwLjIsIAogICAgICAgICAgIGRpZmYuZGlyID0gImh5cG8iLCB0aXRsZSA9ICJwcm9iZXMgd2VyZSBmb3VuZCB3aXRoIDEwMCUgb2Ygc2FtcGxlcyBhbmQgbm90IHdpdGggMjAlIikKYGBgCgojIyBJZGVudGlmeWluZyBwdXRhdGl2ZSBwcm9iZS1nZW5lIHBhaXJzCgpUaGlzIHN0ZXAgaXMgdG8gbGluayBlbmhhbmNlciBwcm9iZXMgd2l0aCBtZXRoeWxhdGlvbiBjaGFuZ2VzIHRvIHRhcmdldCBnZW5lcyB3aXRoIGV4cHJlc3Npb24KY2hhbmdlcyBhbmQgcmVwb3J0IHRoZSBwdXRhdGl2ZSB0YXJnZXQgZ2VuZSBmb3Igc2VsZWN0ZWQgcHJvYmVzLiBUaGlzIGlzIGNhcnJpZWQgb3V0CmJ5IGZ1bmN0aW9uIGBnZXQucGFpcmAuIAoKIyMjIERlc2NyaXB0aW9uCkZpcnN0LCB0aGUgZnVuY3Rpb24gYGdldC5wYWlyYCBmb3IgYWRkaXRpb25hbCBzdHJpbmdlbmN5IGFuZCB0byBhdm9pZCBjb3JyZWxhdGlvbnMgZHVlIHRvIG5vbi1jYW5jZXIgY29udGFtaW5hdGlvbiwgCnNlbGVjdHMgb25seSB0aG9zZSBkaXN0YWwgcHJvYmVzIHRoYXQgaGFkIGRpZmZlcmVudGlhbCBtZXRoeWxhdGlvbiBhcyBkZWZpbmVkIGFib3ZlLCAKYW5kIHdoZXJlIGF0IGxlYXN0IDVcJSBvZiBhbGwgc2FtcGxlcyAoY29tYmluaW5nIHR1bW9yIGFuZCBub3JtYWwpIGhhZCBiZXRhIHZhbHVlcyA+IDAuMy4KIFdlIHVzdWFsbHkgY2FsbCBsb2N1cyB1bm1ldGh5bGF0ZWQgd2hlbiB0aGUgbWV0aHlsYXRpb24gdmFsdWUgPCAwLjMgYW5kIG1ldGh5bGF0ZWQgCiB3aGVuIHRoZSBtZXRoeWxhdGlvbiB2YWx1ZSA+IDAuMy4gCkJhc2ljYWxseSwgdGhpcyBzdGVwIHdpbGwgbWFrZSBzdXJlIHdlIGhhdmUgYXQgbGVhc3QgYSBwZXJjZW50YWdlIG9mIGJldGEgdmFsdWVzIApsZXNzZXIgdGhhbiBLIGFuZCBuIHBlcmNlbnRhZ2Ugb2YgYmV0YSB2YWx1ZXMgZ3JlYXRlciBLLiAKRm9yIGV4YW1wbGUsIGlmIHBlcmNlbnRhZ2UgaXMgNVwlLCB0aGUgbnVtYmVyIG9mIHNhbXBsZXMgMTAwIGFuZCBgSyA9IDAuM2AsIAp0aGlzIGZpbHRlciB3aWxsIHNlbGVjdCBwcm9iZXMgdGhhdCB3ZSBoYXZlIGF0IGxlYXN0IDUgKDVcJSBvZiAxMDBcJSkgc2FtcGxlcyBoYXZlIGJldGEgCnZhbHVlcyA+IDAuMyBhbmQgYXQgbGVhc3QgNSBzYW1wbGVzIGhhdmUgYmV0YSB2YWx1ZXMgPCAwLjMuClRoaXMgZmlsdGVyIGlzIGltcG9ydGFudCBhcyB0cnVlIHByb21vdGVycyBhbmQgZW5oYW5jZXJzIHVzdWFsbHkgaGF2ZSBhIHByZXR0eSBsb3cgCnZhbHVlIChvZiBjb3Vyc2UgcHVyaXR5IGNhbiBzY3JldyB0aGF0IHVwKS4gIAp3ZSBvZnRlbiBzZWUgbG90cyBvZiBQTUQgcHJvYmVzIGFjcm9zcyB0aGUgZ2Vub21lIHdpdGggaW50ZXJtZWRpYXRlIHZhbHVlcyBsaWtlIDAuNC4gIApDaG9vc2luZyBhIHZhbHVlIG9mIDAuMyB3aWxsIGNlcnRhaW5seSBnaXZlIHNvbWUgZmFsc2UgbmVnYXRpdmVzLCBidXQgbm90IGNvbXBhcmVkCnRvIHRoZSBudW1iZXIgb2YgZmFsc2UgcG9zaXRpdmVzIHdlIHRob3VnaHQgd2UgbWlnaHQgZ2V0IHdpdGhvdXQgdGhpcyBmaWx0ZXIuClBsZWFzZSBzZWUgdGhlIGRvY3VtZW50YXRpb24gZm9yIHRoZSBmdW5jdGlvbiBgcHJlQXNzb2NpYXRpb25Qcm9iZUZpbHRlcmluZ2AuCgpBZnRlciwgZm9yIGVhY2ggZGlzdGFsIHByb2JlIHdpdGggZGlmZmVyZW50aWFsIG1ldGh5bGF0aW9uIGFuZCBwYXNzaW5nIAp0aGlzIGZpbHRlciwgdGhlIGNsb3Nlc3QgMTAgdXBzdHJlYW0gCmdlbmVzIGFuZCB0aGUgY2xvc2VzdCAxMCBkb3duc3RyZWFtIGdlbmVzIHdlcmUgdGVzdGVkIGZvciBjb3JyZWxhdGlvbiBiZXR3ZWVuIAptZXRoeWxhdGlvbiBvZiB0aGUgcHJvYmUgYW5kIGV4cHJlc3Npb24gb2YgdGhlIGdlbmUuIFRvIHNlbGVjdCB0aGVzZSBnZW5lcywgCnRoZSBwcm9iZS1nZW5lIGRpc3RhbmNlIHdhcyBkZWZpbmVkIGFzIHRoZSBkaXN0YW5jZSBmcm9tIHRoZSBwcm9iZSB0byBhIHRyYW5zY3JpcHRpb24gCnN0YXJ0IHNpdGUgc3BlY2lmaWVkIGJ5IHRoZSBFTlNFTUJMIGdlbmUgYW5ub3RhdGlvbi4gVGh1cywgZXhhY3RseSAyMCBzdGF0aXN0aWNhbCAKdGVzdHMgd2VyZSBwZXJmb3JtZWQgZm9yIGVhY2ggcHJvYmUsIGFzIGZvbGxvd3MuIEZvciBlYWNoIHByb2JlLWdlbmUgcGFpciwgCnRoZSBzYW1wbGVzIChhbGwgZXhwZXJpbWVudCBzYW1wbGVzIGFuZCBjb250cm9sIHNhbXBsZXMpIHdlcmUgZGl2aWRlZCBpbnRvIHR3byAKZ3JvdXBzOiB0aGUgTSBncm91cCwgd2hpY2ggY29uc2lzdGVkIG9mIHRoZSB1cHBlciBtZXRoeWxhdGlvbiBxdWludGlsZSAodGhlIDIwJQpvZiBzYW1wbGVzIHdpdGggdGhlIGhpZ2hlc3QgbWV0aHlsYXRpb24gYXQgdGhlIGVuaGFuY2VyIHByb2JlKSwgYW5kIHRoZSBVIGdyb3VwLCAKd2hpY2ggY29uc2lzdGVkIG9mIHRoZSBsb3dlc3QgbWV0aHlsYXRpb24gcXVpbnRpbGUgKHRoZSAyMCUgb2Ygc2FtcGxlcyB3aXRoIHRoZSAKbG93ZXN0IG1ldGh5bGF0aW9uLikgVGhlIDIwJSBpbGUgY3V0b2ZmIGlzIGEgY29uZmlndXJhYmxlIHBhcmFtZXRlciBpbiB0aGUgYGdldC5wYWlyYC4KRGVmYXVsdCBpcyAyMCUgYXMgYSBiYWxhbmNlLCB3aGljaCB3b3VsZCBhbGxvdyB1cyB0byBpZGVudGlmeSBjaGFuZ2VzIGluIGEgCm1vbGVjdWxhciBzdWJ0eXBlIG1ha2luZyB1cCBhIG1pbm9yaXR5IChpLmUuIDIwJSkgb2YgY2FzZXMsIHdoaWxlIGFsc28geWllbGRpbmcgCmVub3VnaCBzdGF0aXN0aWNhbCBwb3dlciB0byBtYWtlIHN0cm9uZyBwcmVkaWN0aW9ucy4gRm9yIGVhY2ggY2FuZGlkYXRlIHByb2JlLWdlbmUgcGFpciwgCnRoZSBNYW5uLVdoaXRuZXkgVSB0ZXN0IHdhcyB1c2VkIHRvIHRlc3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IG92ZXJhbGwgZ2VuZSAKZXhwcmVzc2lvbiBpbiBncm91cCBNIHdhcyBncmVhdGVyIG9yIGVxdWFsIHRoYW4gdGhhdCBpbiBncm91cCBVLiAKVGhpcyBub24tcGFyYW1ldHJpYyB0ZXN0IHdhcyB1c2VkIGluIG9yZGVyIHRvIG1pbmltaXplIHRoZSBlZmZlY3RzIApvZiBleHByZXNzaW9uIG91dGxpZXJzLCB3aGljaCBjYW4gIG9jY3VyIGFjcm9zcyBhIHZlcnkgd2lkZSBkeW5hbWljIHJhbmdlLiAKRm9yIGVhY2ggcHJvYmUtZ2VuZSBwYWlyIHRlc3RlZCwgdGhlIHJhdyBwLXZhbHVlIGBQcmAgd2FzIGNvcnJlY3RlZCBmb3IgbXVsdGlwbGUgCmh5cG90aGVzaXMgdXNpbmcgYSBwZXJtdXRhdGlvbiBhcHByb2FjaCBhcyBmb2xsb3dzIChpbXBsZW1lbnRlZCBpbiB0aGUgYGdldC5wZXJtdWAKZnVuY3Rpb24gb2YgdGhlIGByIEJpb2NTdHlsZTo6QmlvY3BrZygiRUxNRVIiKWAgcGFja2FnZSkuClRoZSBnZW5lIGluIHRoZSBwYWlyIHdhcyBoZWxkIGNvbnN0YW50LCBhbmQgeCByYW5kb20gbWV0aHlsYXRpb24gcHJvYmVzIHdlcmUgCnVzZWQgdG8gcGVyZm9ybSB0aGUgc2FtZSBvbmUtdGFpbGVkIFUgdGVzdCwgZ2VuZXJhdGluZyBhIHNldCBvZiB4IHBlcm11dGF0aW9uCnAtdmFsdWVzIChgUHBgKS4gV2UgY2hvc2UgdGhlIHggcmFuZG9tIHByb2JlcyBvbmx5IGZyb20gYW1vbmcgdGhvc2UgdGhhdCB3ZXJlIAoiZGlzdGFsIiAoZ3JlYXRlciB0aGFuIDJrYiBmcm9tIGFuIGFubm90YXRlZCB0cmFuc2NyaXB0aW9uIHN0YXJ0IHNpdGUpLCBpbiBvcmRlciAKdG8gbWFrZSB0aGVzZSBudWxsLW1vZGVsIHByb2JlcyBxdWFsaXRhdGl2ZWx5IHNpbWlsYXIgdG8gdGhlIHByb2JlIGJlaW5nIHRlc3RlZC4gCkFuIGVtcGlyaWNhbCBwLXZhbHVlICRQX2UkIHZhbHVlIHdhcyBjYWxjdWxhdGVkIHVzaW5nIHRoZSBmb2xsb3dpbmcgZm9ybXVsYSAKKHdoaWNoIGludHJvZHVjZXMgYSBwc2V1ZG8tY291bnQgb2YgMSk6CgokJFBlID0gXGZyYWN7bnVtKFBfcCBcbGVxIFBfcikrIDF9e3grMX0kJAoKVGhpcyBzdGVwIGlzIHRoZSBtb3N0IHRpbWUgY29uc3VtaW5nIHN0ZXAgc2luY2UgaXQgcmVxdWlyZXMgYSBsYXJnZSBhbW91bnQgY2FsY3VsYXRpb25zIApmb3IgcGVybXV0YXRpb24uIFRoZSBncmVhdGVyIHRoZSBwZXJtdXRhdGlvbiB0aW1lIGlzLCB0aGUgbG9uZ2VyIGl0IHdpbGwgdGFrZS4gCkl0IGlzIHJlY29tbWVuZGVkIHRvIHVzZSBtdWx0aXBsZSBjb3JlcyBmb3IgdGhpcyBzdGVwLiAxMCwwMDAgcGVybXV0YXRpb25zIGlzIHJlY29tbWVuZGVkIAppZiBoaWdoIGNvbmZpZGVuY2UgcmVzdWx0cyBhcmUgZGVzaXJlZCBidXQgaXQgbWF5IGNvc3Qgc29tZSBob3Vycy4KCklmIGBzYXZlYCBwYXJhbWV0ZXIgb2YgZ2V0LnBhaXIgZnVuY3Rpb24gaXMgdHJ1ZSwgdHdvIGN2cyBmaWxlcyB3aWxsIGJlIG91dHB1dC4gCklmIGBzYXZlYCBwYXJhbWV0ZXIgaXMgZmFsc2UsIGEgZGF0YSBmcmFtZSB3aXRoIHRoZSBzYW1lIGNvbnRlY3QgYXMgdGhlIHNlY29uZCBmaWxlCm1lbnRpb25lZCBhcyBiZWxvdyB3aWxsIGJlIG91dHB1dC4KClRoZSBmaXJzdCBmaWxlIGNvbnRhaW5zIGFsbCBzdGF0aXN0aWMgcmVzdWx0cyBmb3IgYWxsIHByb2JlLWdlbmUgcGFpcnMuIEJhc2VkIG9uIHRoaXMgZmlsZSwgdXNlciAKY2FuIGNoYW5nZSBkaWZmZXJlbnQgUCB2YWx1ZSBvciBzaWcuZGlyIGN1dG9mZiB0byBzZWxlY3QgdGhlIHNpZ25pZmljYW50IHJlc3VsdHMKd2l0aG91dCByZWRvIHRoZSBhbmFseXNpcy4KClRoZSBzZWNvbmQgZmlsZSBjb250YWlucyBzdGF0aXN0aWMgcmVzdWx0cyBmb3IgdGhlIHByb2JlcyB0aGF0IHBhc3MgdGhlIHNpZ25pZmljYW50IGNyaXRlcmlhIChQZSkuCgpCb3RoIGZpbGVzIGNvbnRhaW4gZm91ciBjb2x1bW5zOiBwcm9iZSwgR2VuZUlELCBTeW1ib2wsIERpc3RhbmNlLCBTaWRlcywgUmF3LnAsIFBlLgoKMS4gUHJvYmU6IHRoZSBuYW1lIG9mIHByb2Jlcy4KMi4gR2VuZUlEIGFuZCBTeW1ib2wgaXMgZm9yIHRoZSBnZW5lcyB3aGljaCBhcmUgbGlua2VkIHRvIHRoZSBwcm9iZS4KMy4gRGlzdGFuY2U6IHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHRoZSBwcm9iZSBhbmQgdGhlIGdlbmUuCjQuIFNpZGVzOiByaWdodCAoUikgc2lkZSBvciBsZWZ0IChMKSBzaWRlIG9mIHByb2JlIGFuZCB0aGUgcmFuayBiYXNlZCBvbiBkaXN0YW5jZS4KRm9yIGV4YW1wbGUsIEwzIG1lYW5zIHRoZSBnZW5lIGlzIHRoZSBudW1iZXIgMyBjbG9zZXN0IGdlbmUgZnJvbSB0aGUgbGVmdCBzaWRlIG9mIHRoZSBwcm9iZS4KNS4gUmF3LnA6ICBQIHZhbHVlIGZyb20gdGhlIE1hbm4tV2hpdG5leSBVIHRlc3QgZm9yIGVhY2ggcGFpci4KNi4gUGU6IHRoZSBlbXBpcmljYWwgUCB2YWx1ZSBmb3IgZWFjaCBwYWlyLgoKIyMjIEFyZ3VtZW50cwoKVGhlIG1haW4gYXJndW1lbnRzIG9mIHRoaXMgZnVuY3Rpb24gYXJlOgoKfCBBcmd1bWVudCAgICAgICAgICB8IERlc2NyaXB0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgZGF0YSAgICAgICAgICAgICAgfCBBIG11bHRpQXNzYXlFeHBlcmltZW50IHdpdGggRE5BIG1ldGh5bGF0aW9uIGFuZCBHZW5lIEV4cHJlc3Npb24gZGF0YS4gU2VlIGNyZWF0ZU1BRSBmdW5jdGlvbi4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBuZWFyR2VuZXMgICAgICAgICB8IENhbiBiZSBlaXRoZXIgYSBsaXN0IGNvbnRhaW5pbmcgb3V0cHV0IG9mIEdldE5lYXJHZW5lcyBmdW5jdGlvbiBvciBwYXRoIG9mIHJkYSBmaWxlIGNvbnRhaW5pbmcgb3V0cHV0IG9mIGBHZXROZWFyR2VuZXNgIGZ1bmN0aW9uLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgbWluU3ViZ3JvdXBGcmFjICAgICAgICB8IEEgbnVtYmVyIHJhbmdpbmcgZnJvbSAwIHRvIDEuMCBzcGVjaWZ5aW5nIHRoZSBwZXJjZW50YWdlIG9mIHNhbXBsZXMgdXNlZCB0byBjcmVhdGUgZ3JvdXBzIFUgKHVubWV0aHlsYXRlZCkgYW5kIE0gKG1ldGh5bGF0ZWQpIHVzZWQgdG8gbGluayBwcm9iZXMgdG8gZ2VuZXMuIERlZmF1bHQgaXMgMC40IChsb3dlc3QgcXVpbnRpbGUgc2FtcGxlcyB3aWxsIGJlIGluIHRoZSBVIGdyb3VwIGFuZCB0aGUgaGlnaGVzdCBxdWludGlsZSBzYW1wbGVzIGluIHRoZSBNIGdyb3VwKS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgcGVybXUuc2l6ZSAgICAgICAgfCBBIG51bWJlciBzcGVjaWZ5IHRoZSB0aW1lcyBvZiBwZXJtdWF0aW9uLiBEZWZhdWx0IGlzIDEwMDAwLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBwZXJtdS5kaXIgICAgICAgICB8IEEgcGF0aCB3aGVyZSB0aGUgb3V0cHV0IG9mIHBlcm11dGF0aW9uIHdpbGwgYmUuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IHB2YWx1ZSAgICAgICAgICAgIHwgQSBudW1iZXIgc3BlY2lmeSB0aGUgcmF3IHAtdmFsdWUgY3V0b2ZmIGZvciBkZWZpbmluZyBzaWduZmljYW50IHBhaXJzLiBEZWZhdWx0IGlzIDAuMDUuIEl0IHdpbGwgc2VsZWN0IHRoZSBzaWduaWZpY2FudCBQIHZhbHVlIGN1dG9mZiBiZWZvcmUgY2FsY3VsYXRpbmcgdGhlIGVtcGlyaWNhbCBwLXZhbHVlcy4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBQZSAgICAgICAgICAgICAgICB8IEEgbnVtYmVyIHNwZWNpZnkgdGhlIGVtcGlyaWNhbCBwLXZhbHVlIGN1dG9mZiBmb3IgZGVmaW5pbmcgc2lnbmZpY2FudCBwYWlycy4gRGVmYXVsdCBpcyAwLjAwMS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgZGlyLm91dCAgICAgICAgICAgfCBBIHBhdGggc3BlY2lmeSB0aGUgZGlyZWN0b3J5IGZvciBvdXRwdXRzLiBEZWZhdWx0IGlzIGN1cnJlbnQgZGlyZWN0b3J5ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBkaWZmRXhwICAgICAgICAgICB8IEEgbG9naWMuIERlZmF1bHQgaXMgRkFMU0UuIElmIFRSVUUsIHQgdGVzdCB3aWxsIGJlIGFwcGxpZWQgdG8gdGVzdCB3aGV0aGVyIHB1dGF0aXZlIHRhcmdldCBnZW5lIGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmV0d2VlbiB0d28gZ3JvdXBzLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGdyb3VwLmNvbCAgICAgICAgIHwgQSBjb2x1bW4gZGVmaW5pbmcgdGhlIGdyb3VwcyBvZiB0aGUgc2FtcGxlLiBZb3UgY2FuIHZpZXcgdGhlIGF2YWlsYWJsZSBjb2x1bW5zIHVzaW5nOiBgY29sbmFtZXMoTXVsdGlBc3NheUV4cGVyaW1lbnQ6OmNvbERhdGEoZGF0YSkpYC4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGdyb3VwMSB8IEEgZ3JvdXAgZnJvbSBncm91cC5jb2wuIHwKfCBncm91cDIgfCBBIGdyb3VwIGZyb20gZ3JvdXAuY29sLiB8CnwgY29yZXMgICAgICAgICAgICAgfCBBIGludGVyZ2VyIHdoaWNoIGRlZmluZXMgbnVtYmVyIG9mIGNvcmUgdG8gYmUgdXNlZCBpbiBwYXJhbGxlbCBwcm9jZXNzLiBEZWZhdWx0IGlzIDE6IGRvbid0IHVzZSBwYXJhbGxlbCBwcm9jZXNzLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBmaWx0ZXIucHJvYmVzICAgICB8IFNob3VsZCBmaWx0ZXIgcHJvYmVzIGJ5IHNlbGVjdGluZyBvbmx5IHByb2JlcyB0aGF0IGhhdmUgYXQgbGVhc3QgYSBjZXJ0YWluIG51bWJlciBvZiBzYW1wbGVzIGJlbG93IGFuZCBhYm92ZSBhIGNlcnRhaW4gY3V0LW9mZi4gU2VlIGBwcmVBc3NvY2lhdGlvblByb2JlRmlsdGVyaW5nYCBmdW5jdGlvbi4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgZmlsdGVyLnBvcnRpb24gICAgfCBBIG51bWJlciBzcGVjaWZ5IHRoZSBjdXQgcG9pbnQgdG8gZGVmaW5lIGJpbmFyeSBtZXRobGF0aW9uIGxldmVsIGZvciBwcm9iZSBsb2NpLiBEZWZhdWx0IGlzIDAuMy4gV2hlbiBiZXRhIHZhbHVlIGlzIGFib3ZlIDAuMywgdGhlIHByb2JlIGlzIG1ldGh5bGF0ZWQgYW5kIHZpY2UgdmVyc2EuIEZvciBvbmUgcHJvYmUsIHRoZSBwZXJjZW50YWdlIG9mIG1ldGh5bGF0ZWQgYW5kIHVubWV0aHlsYXRlZCBzYW1wbGVzIHNob3VsZCBiZSBhYm92ZSBmaWx0ZXIucGVyY2VudGFnZSB2YWx1ZS4gT25seSB1c2VkIGlmIGZpbHRlci5wcm9iZXMgaXMgVFJVRS4gU2VlIHByZUFzc29jaWF0aW9uUHJvYmVGaWx0ZXJpbmcgZnVuY3Rpb24uIHwKfCBmaWx0ZXIucGVyY2VudGFnZSB8IE1pbmltdW0gcGVyY2VudGFnZSBvZiBzYW1wbGVzIHRvIGJlIGNvbnNpZGVyZWQgaW4gbWV0aHlsYXRlZCBhbmQgdW5tZXRoeWxhdGVkIGZvciB0aGUgZmlsdGVyLnBvcnRpb24gb3B0aW9uLiBEZWZhdWx0IDUlLiBPbmx5IHVzZWQgaWYgZmlsdGVyLnByb2JlcyBpcyBUUlVFLiBTZWUgcHJlQXNzb2NpYXRpb25Qcm9iZUZpbHRlcmluZyBmdW5jdGlvbi4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGxhYmVsICAgICAgICAgICAgIHwgQSBjaGFyYWN0ZXIgbGFiZWxzIHRoZSBvdXRwdXRzLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8Cnwgc2F2ZSAgICAgICAgICAgICAgfCBUd28gZmlsZXMgd2lsbCBiZSBzYXZlZCBpZiBzYXZlIGlzIHRydWU6IGdldFBhaXIuWFguYWxsLnBhaXJzLnN0YXRpc3RpYy5jc3YgYW5kIGdldFBhaXIuWFgucGFpcnMuc2lnbmlmaWNhbnQuY3N2IChzZWUgZGV0YWlsKS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKIyMjIENvZGUgZXhhbXBsZQpgYGB7cixldmFsPVRSVUUsIG1lc3NhZ2U9RkFMU0V9CiMjIyBpZGVudGlmeSB0YXJnZXQgZ2VuZSBmb3Igc2lnbmlmaWNhbnRseSBoeXBvbWV0aHlsYXRlZCBwcm9iZXMuCgpTaWcucHJvYmVzIDwtIHJlYWQuY3N2KCJyZXN1bHQvZ2V0TWV0aGRpZmYuaHlwby5wcm9iZXMuc2lnbmlmaWNhbnQuY3N2IiwKICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKVssMV0gIApoZWFkKFNpZy5wcm9iZXMpICAjIHNpZ25pZmljYW50bHkgaHlwb21ldGh5bGF0ZWQgcHJvYmVzCgojIyBDb2xsZWN0IG5lYXJieSAyMCBnZW5lcyBmb3IgU2lnLnByb2JlcwpuZWFyR2VuZXMgPC0gR2V0TmVhckdlbmVzKGRhdGEgPSBkYXRhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iZXMgPSBTaWcucHJvYmVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBudW1GbGFua2luZ0dlbmVzID0gMjAsICMgMTAgdXBzdHJlYW0gYW5kIDEwIGRvd3N0cmVhbSBnZW5lcwogICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzID0gcGFyYWxsZWw6OmRldGVjdENvcmVzKCkvMikKCiMjIElkZW50aWZ5IHNpZ25pZmljYW50IHByb2JlLWdlbmUgcGFpcnMKSHlwby5wYWlyIDwtIGdldC5wYWlyKGRhdGEgPSBkYXRhLAogICAgICAgICAgICAgICAgICAgICAgZ3JvdXAuY29sID0gImRlZmluaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgZ3JvdXAxID0gICJQcmltYXJ5IHNvbGlkIFR1bW9yIiwKICAgICAgICAgICAgICAgICAgICAgIGdyb3VwMiA9ICJTb2xpZCBUaXNzdWUgTm9ybWFsIiwKICAgICAgICAgICAgICAgICAgICAgIG5lYXJHZW5lcyA9IG5lYXJHZW5lcywKICAgICAgICAgICAgICAgICAgICAgIG1pblN1Ymdyb3VwRnJhYyA9IDAuNCwgIyAlIG9mIHNhbXBsZXMgdG8gdXNlIGluIHRvIGNyZWF0ZSBncm91cHMgVS9NCiAgICAgICAgICAgICAgICAgICAgICBwZXJtdS5kaXIgPSAicmVzdWx0L3Blcm11IiwKICAgICAgICAgICAgICAgICAgICAgIHBlcm11LnNpemUgPSAxMDAsICMgUGxlYXNlIHNldCB0byAxMDAwMDAgdG8gZ2V0IHNpZ25pZmljYW50IHJlc3VsdHMKICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZSA9IDAuMDUsICAgCiAgICAgICAgICAgICAgICAgICAgICBQZSA9IDAuMDEsICAgICAgICMgUGxlYXNlIHNldCB0byAwLjAwMSB0byBnZXQgc2lnbmlmaWNhbnQgcmVzdWx0cwogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyLnByb2JlcyA9IFRSVUUsICMgU2VlIHByZUFzc29jaWF0aW9uUHJvYmVGaWx0ZXJpbmcgZnVuY3Rpb24KICAgICAgICAgICAgICAgICAgICAgIGZpbHRlci5wZXJjZW50YWdlID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlci5wb3J0aW9uID0gMC4zLAogICAgICAgICAgICAgICAgICAgICAgZGlyLm91dCA9ICJyZXN1bHQiLAogICAgICAgICAgICAgICAgICAgICAgY29yZXMgPSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKS8yLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAiaHlwbyIpCgpkYXRhdGFibGUoSHlwby5wYWlyLCAjIyBzaWduaWZpY2FudCBwcm9iZS1nZW5lIHBhaXJzCiAgICAgICAgICBvcHRpb25zID0gbGlzdChzY3JvbGxYID0gVFJVRSwga2V5cyA9IFRSVUUsIHBhZ2VMZW5ndGggPSA1KSwgCiAgICAgICAgICByb3duYW1lcyA9IFRSVUUpCiMgZ2V0LnBhaXIgYXV0b21hdGljYWxseSBzYXZlIG91dHB1dCBmaWxlcy4gCiNnZXRQYWlyLmh5cG8uYWxsLnBhaXJzLnN0YXRpc3RpYy5jc3YgY29udGFpbnMgc3RhdGlzdGljcyBmb3IgYWxsIHRoZSBwcm9iZS1nZW5lIHBhaXJzLgojZ2V0UGFpci5oeXBvLnBhaXJzLnNpZ25pZmljYW50LmNzdiBjb250YWlucyBvbmx5IHRoZSBzaWduaWZpY2FudCBwcm9iZXMgd2hpY2ggaXMgCiMgc2FtZSB3aXRoIEh5cG8ucGFpci4KZGlyKHBhdGggPSAicmVzdWx0IiwgcGF0dGVybiA9ICJnZXRQYWlyIikgCmBgYAoKCiMjIE1vdGlmIGVucmljaG1lbnQgYW5hbHlzaXMgb24gdGhlIHNlbGVjdGVkIHByb2JlcwoKVGhpcyBzdGVwIGlzIHRvIGlkZW50aWZ5IGVucmljaGVkIG1vdGlmIGluIGEgc2V0IG9mIHByb2JlcyB3aGljaCBpcyBjYXJyaWVkIG91dCBieQpmdW5jdGlvbiBgZ2V0LmVucmljaGVkLm1vdGlmYC4KCiMjIyBEZXNjcmlwdGlvbgoKVGhlIGJ1aWxkLWluIGRhdGEgYFByb2Jlcy5tb3RpZmAgaXMgZ2VuZXJhdGVkIHVzaW5nIEhPTUVSIHdpdGggYSAkcC12YWx1ZSBcbGUgMTBee+KAkzR9JCAKdG8gc2NhbiBhICRccG0yNTBicCQgIHJlZ2lvbiBhcm91bmQgZWFjaCBwcm9iZSB1c2luZyBIT21vIHNhcGllbnMgCkNPbXByZWhlbnNpdmUgTU9kZWwgQ09sbGVjdGlvbiBbaHR0cDovL2hvY29tb2NvLmF1dG9zb21lLnJ1L10oSE9DT01PQ08pIHYxMCBbQGt1bGFrb3Zza2l5MjAxNmhvY29tb2NvXSBwb3NpdGlvbgp3ZWlnaHQgbWF0cmljZXMgKFBXTXMpLiBIT0NPTU9DTyBvZmZlcnMgNjAxIFBNV3MgZWFjaCBoYXMgYSBxdWFsaXR5IHJhdGluZyBmcm9tIEEgdG8gRCB3aGVyZSAKQSByZXByZXNlbnRzIG1vdGlmcyB3aXRoIHRoZSBoaWdoZXN0IGNvbmZpZGVuY2UsIGFuZCBEIG1vdGlmcyBvbmx5IHdlYWtseSBkZXNjcmliZSB0aGUgcGF0dGVybiB3aXRoIGEgCmxpbWl0ZWQgYXBwbGljYXRpb25zIGZvciBxdWFudGl0YXRpdmUgYW5hbHlzZXMuIEJ5IGRlZmF1bHQgb25seSBxdWFsaXR5IEEgYW5kIEIgd2lsbCBiZSB1c2VkIGZvciB0aGUgCk1vdGlmIGVucmljaG1lbnQgYW5hbHlzaXMsIGJ1dCB0aGUgTWluaW11bSBxdWFsaXR5IHNjb3JlIGNhbiBiZSBzZWxlY3RlZCBieSB0aGUgdXNlci4KKEFkZHRpb25hbCBpbmZvcm1hdGlvbiBbaHR0cDovL2hvY29tb2NvLmF1dG9zb21lLnJ1L2hlbHAjZGVzY3JpcHRpb25fcXVhbGl0eV9zY29yZV0oU291cmNlKSAgCltodHRwOi8vbmFyLm94Zm9yZGpvdXJuYWxzLm9yZy9jb250ZW50LzQ0L0QxL0QxMTYuZnVsbCNzZWMtOF0oTW9yZSBpbmZvcm1hdGlvbikpLiAKCkZvciBlYWNoIHByb2JlIHNldCB0ZXN0ZWQgKGkuZS4gdGhlIGxpc3Qgb2YgZ2VuZS1saW5rZWQgaHlwb21ldGh5bGF0ZWQgcHJvYmVzIGluIGEgZ2l2ZW4gZXhwZXJpbWVudCAKZ3JvdXApLCBhIG1vdGlmIGVucmljaG1lbnQgT2RkcyBSYXRpbyBhbmQgYSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCB3ZXJlIApjYWxjdWxhdGVkIHVzaW5nIGZvbGxvd2luZyBmb3JtdWxhczoKJCQgcD0gXGZyYWN7YX17YStifSAkJAokJCBQPSBcZnJhY3tjfXtjK2R9ICQkCiQkIE9kZHNccXVhZCAgUmF0aW8gPSBcZnJhY3tcZnJhY3twfXsxLXB9fXtcZnJhY3tQfXsxLVB9fSAkJAokJCBTRCA9IFxzcXJ0e1xmcmFjezF9e2F9K1xmcmFjezF9e2J9K1xmcmFjezF9e2N9K1xmcmFjezF9e2R9fSAkJAokJCBsb3dlclxxdWFkIGJvdW5kYXJ5XHF1YWQgb2ZccXVhZCAgOTVcJVxxdWFkICBjb25maWRlbmNlXHF1YWQgIGludGVydmFsID0gXGV4cHsoXGxue09SfS1TRCl9ICQkCgp3aGVyZSBgYWAgaXMgdGhlIG51bWJlciBvZiBwcm9iZXMgd2l0aGluIHRoZSBzZWxlY3RlZCBwcm9iZSBzZXQgdGhhdCBjb250YWluIG9uZSAKb3IgbW9yZSBtb3RpZiBvY2N1cnJlbmNlczsgYGJgIGlzIHRoZSBudW1iZXIgb2YgcHJvYmVzIHdpdGhpbiB0aGUgc2VsZWN0ZWQgcHJvYmUgCnNldCB0aGF0IGRvIG5vdCBjb250YWluIGEgbW90aWYgb2NjdXJyZW5jZTsgYGNgIGFuZCBgZGAgYXJlIHRoZSBzYW1lIGNvdW50cyB3aXRoaW4gCnRoZSBlbnRpcmUgZW5oYW5jZXIgcHJvYmUgc2V0LiBBIHByb2JlIHNldCB3YXMgY29uc2lkZXJlZCBzaWduaWZpY2FudGx5IGVucmljaGVkIApmb3IgYSBwYXJ0aWN1bGFyIG1vdGlmIGlmIHRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCBvZiB0aGUgT2RkcyBSYXRpbyB3YXMgCmdyZWF0ZXIgdGhhbiAxLjEgKHNwZWNpZmllZCBieSBvcHRpb24gYGxvd2VyLk9SYCwgMS4xIGlzIGRlZmF1bHQpLCBhbmQgdGhlIG1vdGlmIApvY2N1cnJlZCBhdCBsZWFzdCAxMCB0aW1lcyAoc3BlY2lmaWVkIGJ5IG9wdGlvbiBgbWluLmluY2lkZW5jZWAuIDEwIGlzIGRlZmF1bHQpIGluIAp0aGUgcHJvYmUgc2V0LiBBcyBkZXNjcmliZWQgaW4gdGhlIHRleHQsIE9kZHMgUmF0aW9zIHdlcmUgYWxzbyB1c2VkIGZvciByYW5raW5nIApjYW5kaWRhdGUgbW90aWZzLiAKClRoZXJlIHdpbGwgYmUgdHdvIHJlc3VsdHMgaWYgYHNhdmVgIHBhcmFtZXRlciBvZiBgZ2V0LmVucmljaGVkLm1vdGlmYCBpcyBgVFJVRWAuIFdoZW4gYHNhdmVgIGlzIGBGQUxTRWAsIApvbmx5IHNlY29uZCByZXN1bHQgbWVudGlvbmVkIGJlbG93IHdpbGwgYmUgcmVwb3J0ZWQuCgpUaGUgZmlyc3Qgb25lIGlzIGEgY3N2IGZpbGUuIFRoaXMgZmlsZSBjb250YWlucyB0aGUgT2RkcyBSYXRpbyBhbmQgOTUlIGNvbmZpZGVuY2UgCmludGVydmFsIGZvciB0aGVzZSBPZGRzIFJhdGlvcyB3aGljaCBwYXNzIHRoZSBzaWduZmljYW50IGN1dG9mZiAobG93ZXIuT1IgYW5kIAptaW4uaW5jaWRlbmNlKS4gSXQgY29udGFpbnMgNSBjb2x1bW5zOiBtb3RpZiwgTnVtT2ZQcm9iZXMsIE9SLCBsb3dlck9SIGFuZCB1cHBlck9SLgoKMS4gbW90aWY6IHRoZSBuYW1lIG9mIG1vdGlmLgoyLiBOdW1PZlByb2JlczogdGhlIG51bWJlciBvZiBwcm9iZXMgd2l0aCB0aGlzIG1vdGlmIGluIHRoZSBnaXZlbiBzZXQgb2YgcHJvYmVzCmNvcnJlc3BvbmRpbmcgdG8gbWluLmluY2lkZW5jZSBvcHRpb24uCjMuIE9SOiB0aGUgT2RkcyBSYXRpby4KNC4gbG93ZXJPUjogdGhlIGxvd2VyIGJvdW5kYXJ5IG9mIDk1JSBjb25maWRlbmNlIGludGVydmFsLgo1LiB1cHBlck9SOiB0aGUgdXBwZXIgYm91bmRhcnkgb2YgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwuCgpUaGUgc2Vjb25kIGZpbGUgaXMgYSByZGEgZmlsZSBsaXN0aW5nIGVhY2ggZW5yaWNoZWQgbW90aWYgYW5kIHRoZSBwcm9iZXMgY29udGFpbmluZwp0aGUgbW90aWYuCgojIyMgQXJndW1lbnRzCgpUaGUgbWFpbiBhcmd1bWVudHMgb2YgdGhpcyBmdW5jdGlvbiBhcmU6Cgp8IEFyZ3VtZW50IHwgRGVzY3JpcHRpb24gfAp8LS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfAp8IGRhdGEgfCBBIG11bHRpIEFzc2F5IEV4cGVyaW1lbnQgZnJvbSAgY3JlYXRlTUFFIGZ1bmN0aW9uLiBJZiBzZXQgYW5kIHByb2Jlcy5tb3RpZi9iYWNrZ3JvdW5kIHByb2JlcyBhcmUgbWlzc2luZyB0aGlzIHdpbGwgYmUgdXNlZCB0byBnZXQgdGhpcyBvdGhlciB0d28gYXJndW1lbnRzIGNvcnJlY3RseS4gVGhpcyBhcmd1bWVudCBpcyBub3QgcmVxdWlyZSwgeW91IGNhbiBzZXQgcHJvYmVzLm1vdGlmIGFuZCB0aGUgYmFja2Fncm91bmQucHJvYmVzIG1hbnVhbGx5LiB8CnwgcHJvYmVzLm1vdGlmIHwgQSBtYXRyaXggY29udGFpbnMgbW90aWZzIG9jY3VycmVuY2Ugd2l0aGluIHByb2JlcyByZWdpb25zLiBQcm9iZXMubW90aWYgaW4gRUxNRVIuZGF0YSB3aWxsIGJlIHVzZWQgaWYgcHJvYmVzLm1vdGlmIGlzIG1pc3NpbmcgKGRldGFpbCBzZWUgUHJvYmVzLm1vdGlmLmhnMTkuNDUwSykuIHwKfCBwcm9iZXMgfCBBIHZlY3RvciBsaXN0cyB0aGUgbmFtZSBvZiBwcm9iZXMgdG8gZGVmaW5lIHRoZSBzZXQgb2YgcHJvYmVzIGluIHdoaWNoIG1vdGlmIGVucmljaG1lbnQgT1IgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWwgd2lsbCBiZSBjYWxjdWxhdGVkLiB8CnwgbWluLm1vdGlmLnF1YWxpdHkgfCBNaW5pbXVtIG1vdGlmIHF1YWxpdHkgc2NvcmUgdG8gY29uc2lkZXIuIFBvc3NpYmxlIHZhbHVsZXM6IEEsIEIsIEMgLCBELCBBUyAoQSBhbmQgUyksIEJTIChBLCBCIGFuZCBTKSwgQ1MgKEEsIEIgLCBDIGFuZCBTKSwgRFMgKGFsbCAtIGRlZmF1bHQpIERlc2NyaXB0aW9uOiBFYWNoIFBXTSBoYXMgYSBxdWFsaXR5IHJhdGluZyBmcm9tIEEgdG8gRCB3aGVyZSBBIHJlcHJlc2VudHMgbW90aWZzIHdpdGggdGhlIGhpZ2hlc3QgY29uZmlkZW5jZSwgYW5kIEQgbW90aWZzIG9ubHkgd2Vha2x5IGRlc2NyaWJlIHRoZSBwYXR0ZXJuIHdpdGggYSBsaW1pdGVkIGFwcGxpY2F0aW9ucyBmb3IgcXVhbnRpdGF0aXZlIGFuYWx5c2VzLiBTcGVjaWFsIFMgcXVhbGl0eSBtYXJrcyB0aGUgc2luZ2xlLWJveCBtb3RpZnMgKHNlY29uZGFyeSBtb3RpZikuIFNvdXJjZTogaHR0cDovL2hvY29tb2NvLmF1dG9zb21lLnJ1L2hlbHAjZGVzY3JpcHRpb25fcXVhbGl0eV9zY29yZSBNb3JlIGluZm9ybWF0aW9uOiBodHRwOi8vbmFyLm94Zm9yZGpvdXJuYWxzLm9yZy9jb250ZW50LzQ0L0QxL0QxMTYuZnVsbCNzZWMtOCB8CnwgYmFja2dyb3VuZC5wcm9iZXMgfCBBIHZlY3RvciBsaXN0cyBuYW1lIG9mIHByb2JlcyB3aGljaCBhcmUgY29uc2lkZXJlZCBhcyBiYWNrZ3JvdW5kIGZvciBtb3RpZi5lbnJpY2htZW50IGNhbGN1bGF0aW9uIChzZWUgZGV0YWlsKS4gfAp8IGxvd2VyLk9SIHwgQSBudW1iZXIgc3BlY2lmaWVzIHRoZSBzbWFsbGVzdCBsb3dlciBib3VuZGFyeSBvZiA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgT2RkcyBSYXRpby4gVGhlIG1vdGlmIHdpdGggaGlnaGVyIGxvd2VyIGJvdWRuYXJ5IG9mIDk1JSBjb25maWRlbmNlIGludGVydmFsIGZvciBPZGRzIFJhdGlvIHRoYW4gdGhlIG51bWJlciBhcmUgdGhlIHNpZ25pZmljYW50bHkgZW5yaWNoZWQgbW90aWZzIChkZXRhaWwgc2VlIHJlZmVyZW5jZSkuIHwKfCBtaW4uaW5jaWRlbmNlIHwgQSBub24tbmVnYXRpdmUgaW50ZWdlciBzcGVjaWZpZXMgdGhlIG1pbmltdW0gaW5jaWRlbmNlIG9mIG1vdGlmIGluIHRoZSBnaXZlbiBwcm9iZXMgc2V0LiAxMCBpcyBkZWZhdWx0LiB8CnwgZGlyLm91dCB8IEEgcGF0aC4gU3BlY2lmaWVzIHRoZSBkaXJlY3RvcnkgZm9yIG91dHB1dHMuIERlZmF1bHQgaXMgY3VycmVudCBkaXJlY3RvcnkgfAp8IGxhYmVsIHwgQSBjaGFyYWN0ZXIuIExhYmVscyB0aGUgb3V0cHV0cyBzdWNoIGFzICJoeXBvIiwgImh5cGVyIiB8Cnwgc2F2ZSB8IElmIHNhdmUgaXMgVFVSRSwgdHdvIGZpbGVzIHdpbGwgYmUgc2F2ZWQ6IGdldE1vdGlmLlhYLmVucmljaGVkLm1vdGlmcy5yZGEgYW5kIGdldE1vdGlmLlhYLm1vdGlmLmVucmljaG1lbnQuY3N2IChzZWUgZGV0YWlsKS4gfAoKIyMjIENvZGUgZXhhbXBsZQpgYGB7cixldmFsPVRSVUUsIG1lc3NhZ2U9RkFMU0V9CiMjIGlkZW50aWZ5IGVucmljaGVkIG1vdGlmIGZvciBzaWduaWZpY2FudGx5IGh5cG9tZXRoeWxhdGVkIHByb2JlcyB3aGljaCAKIyNoYXZlIHB1dGF0aXZlIHRhcmdldCBnZW5lcy4KClNpZy5wcm9iZXMucGFpcmVkIDwtIHJlYWQuY3N2KCJyZXN1bHQvZ2V0UGFpci5oeXBvLnBhaXJzLnNpZ25pZmljYW50LmNzdiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpWywxXSAgCmhlYWQoU2lnLnByb2Jlcy5wYWlyZWQpICMgc2lnbmlmaWNhbnRseSBoeXBvbWV0aHlsYXRlZCBwcm9iZXMgd2l0aCBwdXRhdGl2ZSB0YXJnZXQgZ2VuZXMKCmVucmljaGVkLm1vdGlmIDwtIGdldC5lbnJpY2hlZC5tb3RpZihkYXRhID0gZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5tb3RpZi5xdWFsaXR5ID0gIkIiLCAjIERlZmF1bHQ6IG9wdGlvbnMgQSwgQiwgQywgRAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYmVzID0gU2lnLnByb2Jlcy5wYWlyZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyLm91dCA9ICJyZXN1bHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gImh5cG8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluLmluY2lkZW5jZSA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIuT1IgPSAxLjEpCm5hbWVzKGVucmljaGVkLm1vdGlmKSAgIyBlbnJpY2hlZCBtb3RpZnMKaGVhZChlbnJpY2hlZC5tb3RpZlsiUDczX0hVTUFOLkgxME1PLkEiXSkgIyMgcHJvYmVzIGluIHRoZSBnaXZlbiBzZXQgdGhhdCBoYXZlIFRQNTMgbW90aWYuCgojIGdldC5lbnJpY2hlZC5tb3RpZiBhdXRvbWF0aWNhbGx5IHNhdmUgb3V0cHV0IGZpbGVzLiAKIyBnZXRNb3RpZi5oeXBvLmVucmljaGVkLm1vdGlmcy5yZGEgY29udGFpbnMgZW5yaWNoZWQgbW90aWZzIGFuZCB0aGUgcHJvYmVzIHdpdGggdGhlIG1vdGlmLiAKIyBnZXRNb3RpZi5oeXBvLm1vdGlmLmVucmljaG1lbnQuY3N2IGNvbnRhaW5zIHN1bW1hcnkgb2YgZW5yaWNoZWQgbW90aWZzLgpkaXIocGF0aCA9ICJyZXN1bHQiLCBwYXR0ZXJuID0gImdldE1vdGlmIikgCgojIG1vdGlmIGVucmljaG1lbnQgZmlndXJlIHdpbGwgYmUgYXV0b21hdGljYWxseSBnZW5lcmF0ZWQuCmRpcihwYXRoID0gInJlc3VsdCIsIHBhdHRlcm4gPSAibW90aWYuZW5yaWNobWVudC5wZGYiKSAKYGBgCgoKIyMgSWRlbnRpZnlpbmcgcmVndWxhdG9yeSBURnMKClRoaXMgc3RlcCBpcyB0byBpZGVudGlmeSByZWd1bGF0b3J5IFRGIHdob3NlIGV4cHJlc3Npb24gYXNzb2NpYXRlcyB3aXRoIFRGIGJpbmRpbmcgbW90aWYgCkROQSBtZXRoeWxhdGlvbiB3aGljaCBpcyBjYXJyaWVkIG91dCBieSBmdW5jdGlvbiBgZ2V0LlRGc2AuCgojIyMgRGVzY3JpcHRpb24KRm9yIGVhY2ggbW90aWYgY29uc2lkZXJlZCB0byBiZSBlbnJpY2hlZCB3aXRoaW4gYSBwYXJ0aWN1bGFyIHByb2JlIHNldCwgZnVuY3Rpb24gd2lsbApjb21wYXJlIHRoZSBhdmVyYWdlIEROQSBtZXRoeWxhdGlvbiBhdCBhbGwgZGlzdGFsIGVuaGFuY2VyIHByb2JlcyB3aXRoaW4gJFxwbTI1MGJwJCAgCm9mIGEgbW90aWYgb2NjdXJyZW5jZSwgdG8gdGhlIGV4cHJlc3Npb24gb2YgaHVtYW4gVEZzLiBBIHN0YXRpc3RpY2FsIHRlc3QgCndhcyBwZXJmb3JtZWQgZm9yIGVhY2ggbW90aWYtVEYgcGFpciwgYXMgZm9sbG93cy4gVGhlIHNhbXBsZXMgKGFsbCBjb250cm9sIGFuZCAKZXhwZXJpbWVudCBzYW1wbGVzKSB3ZXJlIGRpdmlkZWQgaW50byB0d28gZ3JvdXBzOiB0aGUgTSBncm91cCwgd2hpY2ggY29uc2lzdGVkIApvZiB0aGUgMjAlIG9mIHNhbXBsZXMgd2l0aCB0aGUgaGlnaGVzdCBhdmVyYWdlIG1ldGh5bGF0aW9uIGF0IGFsbCBtb3RpZi1hZGphY2VudCAKcHJvYmVzLCBhbmQgdGhlIFUgZ3JvdXAsIHdoaWNoIGNvbnNpc3RlZCBvZiB0aGUgMjAlIG9mIHNhbXBsZXMgd2l0aCB0aGUgbG93ZXN0IAptZXRoeWxhdGlvbi4gVGhlIDIwdGggcGVyY2VudGlsZSBjdXRvZmYgaXMgYSBwYXJhbWV0ZXIgdG8gdGhlIGdldC5URnMgZnVuY3Rpb24gCmFuZCB3YXMgc2V0IHRvIGFsbG93IGZvciBpZGVudGlmaWNhdGlvbiBvZiBtb2xlY3VsYXIgc3VidHlwZXMgcHJlc2VudCBpbiAyMCUgb2YgCmNhc2VzLiBGb3IgZWFjaCBjYW5kaWRhdGUgbW90aWYtVEYgcGFpciwgdGhlIE1hbm4tV2hpdG5leSBVIHRlc3Qgd2FzIHVzZWQgdG8gdGVzdCAKdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IG92ZXJhbGwgZ2VuZSBleHByZXNzaW9uIGluIGdyb3VwIE0gd2FzIGdyZWF0ZXIgb3IgZXF1YWwgCnRoYW4gdGhhdCBpbiBncm91cCBVLiBUaGlzIG5vbi1wYXJhbWV0cmljIHRlc3Qgd2FzIHVzZWQgaW4gb3JkZXIgdG8gbWluaW1pemUgdGhlIAplZmZlY3RzIG9mIGV4cHJlc3Npb24gb3V0bGllcnMsIHdoaWNoIGNhbiBvY2N1ciBhY3Jvc3MgYSB2ZXJ5IHdpZGUgZHluYW1pYyByYW5nZS4gCkZvciBlYWNoIG1vdGlmIHRlc3RlZCwgdGhpcyByZXN1bHRlZCBpbiBhIHJhdyBwLXZhbHVlICgkUF9yJCkgZm9yIGVhY2ggb2YgdGhlIGh1bWFuIFRGcy4KQWxsIFRGcyB3ZXJlIHJhbmtlZCBieSB0aGUgJC1sb2dfezEwfShQX3tyfSkkLCBhbmQgdGhvc2UgZmFsbGluZyB3aXRoaW4gdGhlIHRvcCA1JSBvZiAKdGhpcyByYW5raW5nIHdlcmUgY29uc2lkZXJlZCBjYW5kaWRhdGUgdXBzdHJlYW0gcmVndWxhdG9ycy4gVGhlIGJlc3QgdXBzdHJlYW0gClRGcyB3aGljaCBhcmUga25vd24gcmVjb2duaXplZCB0aGUgbW90aWYgd2FzIGF1dG9tYXRpY2FsbHkgZXh0cmFjdGVkIGFzIHB1dGF0aXZlIApyZWd1bGF0b3J5IFRGcy4KCklmIGBzYXZlYCBwYXJhbWV0ZXIgb2YgYGdldC5URnNgIGZ1bmN0aW9uIGlzIHRydWUsIHR3byBmaWxlcyB3aWxsIGJlIGdlbmVyYXRlZC4gCklmIGBzYXZlYCBwYXJhbWV0ZXIgaXMgYEZBTFNFYCwgb25seSBhIGRhdGEgZnJhbWUgY29udGFpbmluZyB0aGUgc2FtZSBjb250ZW50IAp3aXRoIHRoZSBmaXJzdCBmaWxlIG1lbnRpb25lZCBiZWxvdyB3aWxsIGJlIG91dHB1dC4KClRoZSBmaXJzdCBvbmUgY3N2IGZpbGUuIFRoaXMgZmlsZSBjb250YWluIHRoZSByZWd1bGF0b3J5IFRGIHNpZ25pZmljYW50bHkgCmFzc29jaWF0ZSB3aXRoIGF2ZXJhZ2UgRE5BIG1ldGh5bGF0aW9uIGF0IHBhcnRpY3VsYXIgbW90aWYgc2l0ZXMuIEl0IGNvbnRhaW5zIDYgCmNvbHVtbnM6IG1vdGlmLCB0b3AucG90ZW50aWFsLlRGLmZhbWlseSwgdG9wLnBvdGVudGlhbC5URi5zdWJmYW1pbHksIApwb3RlbnRpYWwuVEZzLmZhbWlseSwgcG90ZW50aWFsLlRGcy5zdWJmYW1pbHkgYW5kIHRvcF81cGVyY2VudC4KCjEuIG1vdGlmOiB0aGUgbmFtZXMgb2YgbW90aWYuCjIuIHRvcC5wb3RlbnRpYWwuVEYuZmFtaWx5OiB0aGUgaGlnaGVzdCByYW5raW5nIHVwc3RyZWFtIFRGcyB3aGljaCBhcmUga25vd24gcmVjb2duaXplZCB0aGUgbW90aWYuIEZpcnN0IGl0ZW0gaW4gcG90ZW50aWFsLlRGcy5mYW1pbHkKMy4gdG9wLnBvdGVudGlhbC5URi5zdWJmYW1pbHk6IHRoZSBoaWdoZXN0IHJhbmtpbmcgdXBzdHJlYW0gVEZzIHdoaWNoIGFyZSBrbm93biByZWNvZ25pemVkIHRoZSBtb3RpZi4gRmlyc3QgaXRlbSBpbiBwb3RlbnRpYWwuVEZzLnN1YmZhbWlseQo0LiBwb3RlbnRpYWwuVEZzLmZhbWlseTogVEZzIHdoaWNoIGFyZSB3aXRoaW4gdG9wIDUlIGxpc3QgYW5kIGFyZSBrbm93biByZWNvZ25pemVkIHRoZSBtb3RpZiAgKGNvbnNpZGVyaW5nIGZhbWlseSBjbGFzc2lmaWNhdGlvbikuCjUuIHBvdGVudGlhbC5URnMuc3ViZmFtaWx5OiBURnMgd2hpY2ggYXJlIHdpdGhpbiB0b3AgNSUgbGlzdCBhbmQgYXJlIGtub3duIHJlY29nbml6ZWQgdGhlIG1vdGlmIChjb25zaWRlcmluZyBzdWJmYW1pbHkgY2xhc3NpZmljYXRpb24pLgo2LiB0b3BfNXBlcmNlbnQ6IGFsbCBURnMgd2hpY2ggYXJlIHdpdGhpbiB0b3AgNSUgbGlzdC4KClRoZSBzZWNvbmQgZmlsZSBpcyByZGEgZmlsZS4gVGhpcyBmaWxlIGNvbnRhaW5zIGEgbWF0cml4IHN0b3JpbmcgdGhlIHN0YXRpc3RpYyAKcmVzdWx0cyBmb3IgYXNzb2NpYXRpb25zIGJldHdlZW4gVEZzIChyb3cpIGFuZCBhdmVyYWdlIEROQSBtZXRoeWxhdGlvbiAKYXQgbW90aWZzIChjb2x1bW4pLiBUaGlzIG1hdHJpeCBjYW4gYmUgdXNlIHRvIGdlbmVyYXRlIFRGIHJhbmtpbmcgcGxvdHMgYnkgZnVuY3Rpb24KVEYucmFuay5wbG90LgoKIyMjIEFyZ3VtZW50cwoKClRoZSBtYWluIGFyZ3VtZW50cyBvZiB0aGlzIGZ1bmN0aW9uIGFyZToKCnwgQXJndW1lbnQgfCBEZXNjcmlwdGlvbiB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfAp8IGRhdGEgfCBBIG11bHRpQXNzYXlFeHBlcmltZW50IHdpdGggRE5BIG1ldGh5bGF0aW9uIGFuZCBHZW5lIEV4cHJlc3Npb24gZGF0YS4gU2VlIGBjcmVhdGVNQUVgIGZ1bmN0aW9uLiB8CnwgZW5yaWNoZWQubW90aWYgfCBBIGxpc3QgY29udGFpbmluZyBvdXRwdXQgb2YgZ2V0LmVucmljaGVkLm1vdGlmIGZ1bmN0aW9uIG9yIGEgcGF0aCBvZiBYWC5yZGEgZmlsZSBjb250YWluaW5nIG91dHB1dCBvZiBnZXQuZW5yaWNoZWQubW90aWYgZnVuY3Rpb24uIHwKfCBURnMgfCBBIGRhdGEuZnJhbWUgY29udGFpbmluZyBURiBHZW5lSUQgYW5kIFN5bWJvbCBvciBhIHBhdGggb2YgWFguY3N2IGZpbGUgY29udGFpbmluZyBURiBHZW5lSUQgYW5kIFN5bWJvbC4gSWYgbWlzc2luZywgaHVtYW4uVEYgbGlzdCB3aWxsIGJlIHVzZWQgKGh1bWFuLlRGIGRhdGEgaW4gRUxNRVIuZGF0YSkuIEZvciBkZXRhaWwgaW5mb3JtYXRpb24sIHJlZmVyIHRoZSByZWZlcmVuY2UgcGFwZXIuIHwKfCBtb3RpZi5yZWxldmFudC5URnMgfCBBIGxpc3QgY29udGFpbmluZyBtb3RpZiBhcyBuYW1lcyBhbmQgcmVsYXZlbnQgVEZzIGFzIGNvbnRlbnRzIGZvciBlYWNoIGxpc3QgZWxlbWVudCBvciBhIHBhdGggb2YgWFgucmRhIGZpbGUgY29udGFpbmluZyBhIGxpc3QgYXMgYWJvdmUuIElmIG1pc3NpbmcsIFRGQ2xhc3MgY2xhc3NpZmljYXRpb24gd2lsbCBiZSB1c2VkLiBTZWUgZnVuY3Rpb24gYGNyZWF0ZU1vdGlmUmVsZXZhbnRUZnNgfAp8IGdyb3VwLmNvbCAgICAgICAgIHwgQSBjb2x1bW4gZGVmaW5pbmcgdGhlIGdyb3VwcyBvZiB0aGUgc2FtcGxlLiBZb3UgY2FuIHZpZXcgdGhlIGF2YWlsYWJsZSBjb2x1bW5zIHVzaW5nOiBgY29sbmFtZXMoTXVsdGlBc3NheUV4cGVyaW1lbnQ6OmNvbERhdGEoZGF0YSkpYC4gICAgICAgICAgICAgICAgCnwgZ3JvdXAxIHwgQSBncm91cCBmcm9tIGdyb3VwLmNvbC4gfAp8IGdyb3VwMiB8IEEgZ3JvdXAgZnJvbSBncm91cC5jb2wuIHwKfCBtaW5TdWJncm91cEZyYWMgfCAgQSBudW1iZXIgcmFuZ2luZyBmcm9tIDAgdG8gMSBzcGVjaWZ5aW5nIHRoZSBwZXJjZW50YWdlIG9mIHNhbXBsZXMgdXNlZCB0byBjcmVhdGUgdGhlIGdyb3VwcyBVICh1bm1ldGh5bGF0ZWQpICBhbmQgTSAobWV0aHlsYXRlZCkgdXNlZCB0byBsaW5rIHByb2JlcyB0byBURiBleHByZXNzaW9uLiAgRGVmYXVsdCBpcyAwLjQgKGxvd2VzdCBxdWludGlsZSBvZiBhbGwgc2FtcGxlcyB3aWxsIGJlIGluIHRoZSAgVSBncm91cCBhbmQgdGhlIGhpZ2hlc3QgcXVpbnRpbGUgb2YgYWxsIHNhbXBsZXMgaW4gdGhlIE0gZ3JvdXApLiB8CnwgZGlyLm91dCB8IEEgcGF0aCBzcGVjaWZpZXMgdGhlIGRpcmVjdG9yeSBmb3Igb3V0cHV0cyBvZiBgZ2V0LnBhaXJgIGZ1bmN0aW9uLiBEZWZhdWx0IGlzIGN1cnJlbnQgZGlyZWN0b3J5IHwKfCBsYWJlbCB8IEEgY2hhcmFjdGVyIGxhYmVscyB0aGUgb3V0cHV0cy4gfAp8IGNvcmVzIHwgQSBpbnRlcmdlciB3aGljaCBkZWZpbmVzIHRoZSBudW1iZXIgb2YgY29yZXMgdG8gYmUgdXNlZCBpbiBwYXJhbGxlbCBwcm9jZXNzLiBEZWZhdWx0IGlzIDE6IG5vIHBhcmFsbGVsIHByb2Nlc3MuIHwKfCBzYXZlIHwgQSBsb2dpYy4gSWYgc2F2ZSBpcyB0dXJlLCB0d28gZmlsZXMgd2lsbCBiZSBzYXZlZDogZ2V0VEYuWFguc2lnbmlmaWNhbnQuVEZzLndpdGgubW90aWYuc3VtbWFyeS5jc3YgYW5kIGdldFRGLmh5cG8uVEZzLndpdGgubW90aWYucHZhbHVlLnJkYSAoc2VlIGRldGFpbCkuIElmIHNhdmUgaXMgZmFsc2UsIGEgZGF0YSBmcmFtZSBjb250YWlucyB0aGUgc2FtZSBjb250ZW50IHdpdGggdGhlIGZpcnN0IGZpbGUuIHwKCiMjIyBDb2RlIGV4YW1wbGUKYGBge3IgcmVzdWx0cz0naGlkZScsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgaWRlbnRpZnkgcmVndWxhdG9yeSBURiBmb3IgdGhlIGVucmljaGVkIG1vdGlmcwpURiA8LSBnZXQuVEZzKGRhdGEgPSBkYXRhLCAKICAgICAgICAgICAgICBncm91cC5jb2wgPSAiZGVmaW5pdGlvbiIsCiAgICAgICAgICAgICAgZ3JvdXAxID0gICJQcmltYXJ5IHNvbGlkIFR1bW9yIiwKICAgICAgICAgICAgICBncm91cDIgPSAiU29saWQgVGlzc3VlIE5vcm1hbCIsCiAgICAgICAgICAgICAgbWluU3ViZ3JvdXBGcmFjID0gMS4wLAogICAgICAgICAgICAgIGVucmljaGVkLm1vdGlmID0gZW5yaWNoZWQubW90aWYsCiAgICAgICAgICAgICAgZGlyLm91dCA9ICJyZXN1bHQiLCAKICAgICAgICAgICAgICBjb3JlcyA9IDEsIAogICAgICAgICAgICAgIGxhYmVsID0gImh5cG8iKQoKIyBnZXQuVEZzIGF1dG9tYXRpY2FsbHkgc2F2ZSBvdXRwdXQgZmlsZXMuIAojIGdldFRGLmh5cG8uVEZzLndpdGgubW90aWYucHZhbHVlLnJkYSBjb250YWlucyBzdGF0aXN0aWNzIGZvciBhbGwgVEYgd2l0aCBhdmVyYWdlIAojIEROQSBtZXRoeWxhdGlvbiBhdCBzaXRlcyB3aXRoIHRoZSBlbnJpY2hlZCBtb3RpZi4KIyBnZXRURi5oeXBvLnNpZ25pZmljYW50LlRGcy53aXRoLm1vdGlmLnN1bW1hcnkuY3N2IGNvbnRhaW5zIG9ubHkgdGhlIHNpZ25pZmljYW50IHByb2Jlcy4KZGlyKHBhdGggPSAicmVzdWx0IiwgcGF0dGVybiA9ICJnZXRURiIpICAKCiMgVEYgcmFua2luZyBwbG90IGJhc2VkIG9uIHN0YXRpc3RpY3Mgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IGdlbmVyYXRlZC4KZGlyKHBhdGggPSAicmVzdWx0L1RGcmFua1Bsb3RfZmFtaWx5LyIsIHBhdHRlcm4gPSAicGRmIikgCmBgYAoKIyBHZW5lcmF0aW5nIGZpZ3VyZXMKCiMjIFNjYXR0ZXIgcGxvdHMKCkdlbmVyYXRlIHNjYXR0ZXIgcGxvdHMgZm9yIG9uZSBwcm9iZXMnIG5lYXJieSAyMCBnZW5lIGV4cHJlc3Npb24gdnMgRE5BIG1ldGh5bGF0aW9uIGF0IHRoaXMgcHJvYmUuCgpFYWNoIHNjYXR0ZXIgcGxvdCBzaG93cyB0aGUgbWV0aHlsYXRpb24gbGV2ZWwgb2YgYW4gZXhhbXBsZSAgcHJvYmUgY2cxOTQwMzMyMyBpbiBhbGwgTFVTQyBzYW1wbGVzIHBsb3R0ZWQgYWdhaW5zdCB0aGUgZXhwcmVzc2lvbiBvZiBvbmUgb2YgIDIwIGFkamFjZW50IGdlbmVzLgpgYGB7ciByZXN1bHRzPSdoaWRlJywgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9IkVhY2ggc2NhdHRlciBwbG90IHNob3dzIHRoZSBtZXRoeWxhdGlvbiBsZXZlbCBvZiBhbiBleGFtcGxlICBwcm9iZSBjZzE5NDAzMzIzIGluIGFsbCBMVVNDIHNhbXBsZXMgcGxvdHRlZCBhZ2FpbnN0IHRoZSBleHByZXNzaW9uIG9mIG9uZSBvZiAgMjAgYWRqYWNlbnQgZ2VuZXMuIn0Kc2NhdHRlci5wbG90KGRhdGEsCiAgICAgICAgICAgICBieVByb2JlID0gbGlzdChwcm9iZSA9IGMoImNnMTk0MDMzMjMiKSwgbnVtRmxhbmtpbmdHZW5lcyA9IDIwKSwgCiAgICAgICAgICAgICBjYXRlZ29yeSA9ICJkZWZpbml0aW9uIiwgCiAgICAgICAgICAgICBsbSA9IFRSVUUsICMgRHJhdyBsaW5lYXIgcmVncmVzc2lvbiBjdXJ2ZQogICAgICAgICAgICAgc2F2ZSA9IEZBTFNFKSAKYGBgCgojIyMgIFNjYXR0ZXIgcGxvdCBvZiBvbmUgcGFpcgpHZW5lcmF0ZSBhIHNjYXR0ZXIgcGxvdCBmb3Igb25lIHByb2JlLWdlbmUgcGFpci4gRmlndXJlIFxyZWZ7ZmlnOmZpZ3VyZTJ9CgpTY2F0dGVyIHBsb3Qgc2hvd3MgdGhlIG1ldGh5bGF0aW9uIGxldmVsIG9mIGFuIGV4YW1wbGUgcHJvYmUgY2cxOTQwMzMyMyBpbiBhbGwgTFVTQyBzYW1wbGVzIHBsb3R0ZWQgYWdhaW5zdCB0aGUgZXhwcmVzc2lvbiBvZiB0aGUgcHV0YXRpdmUgIHRhcmdldCBnZW5lIFNZVDE0LgpgYGB7ciByZXN1bHRzPSdoaWRlJyxldmFsPVRSVUUsIGZpZy5jYXA9IlNjYXR0ZXIgcGxvdCBzaG93cyB0aGUgbWV0aHlsYXRpb24gbGV2ZWwgb2YgYW4gZXhhbXBsZSBwcm9iZSBjZzE5NDAzMzIzIGluIGFsbCBMVVNDIHNhbXBsZXMgcGxvdHRlZCBhZ2FpbnN0IHRoZSBleHByZXNzaW9uIG9mIHRoZSBwdXRhdGl2ZSAgdGFyZ2V0IGdlbmUgU1lUMTQuIn0Kc2NhdHRlci5wbG90KGRhdGEsCiAgICAgICAgICAgICBieVBhaXIgPSBsaXN0KHByb2JlID0gYygiY2cxOTQwMzMyMyIpLCBnZW5lID0gYygiRU5TRzAwMDAwMTQzNDY5IikpLCAKICAgICAgICAgICAgIGNhdGVnb3J5ID0gImRlZmluaXRpb24iLCBzYXZlID0gVFJVRSwgbG1fbGluZSA9IFRSVUUpIApgYGAKCiMjIyAgVEYgZXhwcmVzc2lvbiB2cy4gYXZlcmFnZSBETkEgbWV0aHlsYXRpb24KR2VuZXJhdGUgc2NhdHRlciBwbG90IGZvciBURiBleHByZXNzaW9uIHZzIGF2ZXJhZ2UgRE5BIG1ldGh5bGF0aW9uIG9mIHRoZSBzaXRlcyAKd2l0aCBjZXJ0YWluIG1vdGlmLgoKRWFjaCBzY2F0dGVyIHBsb3Qgc2hvd3MgdGhlIGF2ZXJhZ2UgIG1ldGh5bGF0aW9uIGxldmVsIG9mIHNpdGVzIHdpdGggdGhlIFRQNTMgbW90aWYgaW4gYWxsIExVU0Mgc2FtcGxlcyBwbG90dGVkIGFnYWluc3QgdGhlIGV4cHJlc3Npb24gb2YgdGhlIHRyYW5zY3JpcHRpb24gZmFjdG9yIFRQNTMsIFRQNjMsIFRQNzMgcmVzcGVjdGl2ZWx5LgoKYGBge3IsZXZhbD1UUlVFLCBmaWcuY2FwPSJFYWNoIHNjYXR0ZXIgcGxvdCBzaG93cyB0aGUgYXZlcmFnZSAgbWV0aHlsYXRpb24gbGV2ZWwgb2Ygc2l0ZXMgd2l0aCB0aGUgVFA1MyBtb3RpZiBpbiBhbGwgTFVTQyBzYW1wbGVzIHBsb3R0ZWQgYWdhaW5zdCB0aGUgZXhwcmVzc2lvbiBvZiB0aGUgdHJhbnNjcmlwdGlvbiBmYWN0b3IgVFA1MywgVFA2MywgVFA3MyByZXNwZWN0aXZlbHkuIn0KbG9hZCgicmVzdWx0L2dldE1vdGlmLmh5cG8uZW5yaWNoZWQubW90aWZzLnJkYSIpCnNjYXR0ZXIucGxvdChkYXRhLAogICAgICAgICAgICAgYnlURiA9IGxpc3QoVEYgPSBjKCJUUDUzIiwiVFA2MyIsIlRQNzMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHByb2JlID0gZW5yaWNoZWQubW90aWZbWyJQNzNfSFVNQU4uSDEwTU8uQSJdXSksIAogICAgICAgICAgICAgY2F0ZWdvcnkgPSAiZGVmaW5pdGlvbiIsCiAgICAgICAgICAgICBzYXZlID0gVFJVRSwgCiAgICAgICAgICAgICBsbV9saW5lID0gVFJVRSkKYGBgCgojIyBTY2hlbWF0aWMgcGxvdApTY2hlbWF0aWMgcGxvdCBzaG93cyBhIGJyZWlmIHZpZXcgb2YgbGlua2FnZXMgYmV0d2VlbiBnZW5lcyBhbmQgcHJvYmVzLgoKIyMjIE5lYXJieSBHZW5lcwpHZW5lcmF0ZSBzY2hlbWF0aWMgcGxvdCBmb3Igb25lIHByb2JlIHdpdGggMjAgbmVhcmJ5IGdlbmVzIGFuZCBsYWJlbCAgdGhlIGdlbmUgc2lnbmlmaWNhbnRseSBsaW5rZWQgd2l0aCB0aGUgcHJvYmUgaW4gcmVkLiAKCgpgYGB7ciByZXN1bHRzPSdoaWRlJywgZXZhbD1UUlVFLGZpZy5oZWlnaHQ9NSwgIGZpZy5jYXA9IlRoZSBzY2hlbWF0aWMgcGxvdCBzaG93cyBwcm9iZSBjb2xvcmVkIGluIGJsdWUgYW5kIHRoZSBsb2NhdGlvbiBvZiBuZWFyYnkgMjAgZ2VuZXMuIFRoZSBnZW5lcyBzaWduaWZpY2FudGx5IGxpbmtlZCB0byB0aGUgcHJvYmUgIHdlcmUgc2hvd24gaW4gcmVkLiIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnNjaGVtYXRpYy5wbG90KHBhaXIgPSBIeXBvLnBhaXIsIAogICAgICAgICAgICAgICBkYXRhID0gZGF0YSwKICAgICAgICAgICAgICAgZ3JvdXAuY29sID0gImRlZmluaXRpb24iLAogICAgICAgICAgICAgICBieVByb2JlID0gImNnMjUzMTIxMjIiLAogICAgICAgICAgICAgICBzYXZlID0gRkFMU0UpCmBgYAoKIyMjIE5lYXJieSBQcm9iZXMKR2VuZXJhdGUgc2NoZW1hdGljIHBsb3QgZm9yIG9uZSBnZW5lIHdpdGggdGhlIHByb2JlcyB3aGljaCB0aGUgZ2VuZSBpcyBzaWduaWZpY2FudGx5IApsaW5rZWQgdG8uCgpgYGB7ciByZXN1bHRzPSdoaWRlJywgZXZhbD1UUlVFLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0xMCwgZmlnLmNhcD0iVGhlIHNjaGVtYXRpYyBwbG90IHNob3dzIHRoZSBnZW5lIGNvbG9yZWQgaW4gcmVkIGFuZCBhbGwgYmx1ZSBjb2xvcmVkIHByb2Jlcywgd2hpY2ggYXJlIHNpZ25pZmljYW50bHkgbGlua2VkIHRvIHRoZSAgZXhwcmVzc2lvbiBvZiB0aGlzIGdlbmUuIn0Kc2NoZW1hdGljLnBsb3QocGFpciA9IEh5cG8ucGFpciwgCiAgICAgICAgICAgICAgIGRhdGEgPSBkYXRhLCAgIAogICAgICAgICAgICAgICBncm91cC5jb2wgPSAiZGVmaW5pdGlvbiIsIAogICAgICAgICAgICAgICBieUdlbmUgPSAiRU5TRzAwMDAwMTQzNDY5IiwgCiAgICAgICAgICAgICAgIHNhdmUgPSBGQUxTRSkKYGBgCgojIyBNb3RpZiBlbnJpY2htZW50IHBsb3QKTW90aWYgIGVucmljaG1lbnQgcGxvdCBzaG93cyB0aGUgZW5yaWNobWVudCBsZXZlbHMgZm9yIHRoZSBzZWxlY3RlZCBtb3RpZnMuIAoKVGhlIHBsb3Qgc2hvd3MgdGhlIE9kZHMgUmF0aW8gKHggYXhpcykgZm9yIHRoZSBzZWxlY3RlZCBtb3RpZnMgd2l0aCBPUiBhYm92ZSAxLjMgYW5kIGxvd2VyIGJvdW5kYXJ5IG9mIE9SIGFib3ZlIDEuMy4gVGhlIHJhbmdlIHNob3dzIHRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgZWFjaCBPZGRzIFJhdGlvCmBgYHtyIHJlc3VsdHM9J2hpZGUnLCBldmFsPVRSVUUsIGZpZy53aWR0aD02LGZpZy5jYXA9IlRoZSBwbG90IHNob3dzIHRoZSBPZGRzIFJhdGlvICh4IGF4aXMpIGZvciB0aGUgc2VsZWN0ZWQgbW90aWZzIHdpdGggT1IgYWJvdmUgMS4zIGFuZCBsb3dlciBib3VuZGFyeSBvZiBPUiBhYm92ZSAxLjMuIFRoZSByYW5nZSBzaG93cyB0aGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIGVhY2ggT2RkcyBSYXRpby4ifQptb3RpZi5lbnJpY2htZW50LnBsb3QobW90aWYuZW5yaWNobWVudCA9ICJyZXN1bHQvZ2V0TW90aWYuaHlwby5tb3RpZi5lbnJpY2htZW50LmNzdiIsIAogICAgICAgICAgICAgICAgICAgICAgc2lnbmlmaWNhbnQgPSBsaXN0KE9SID0gMS4zLGxvd2VyT1IgPSAxLjMpLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gImh5cG8iLCAKICAgICAgICAgICAgICAgICAgICAgIHNhdmUgPSBUUlVFKSAgIyMgZGlmZmVyZW50IHNpZ25maWNhbnQgY3V0IG9mZi4KYGBgCgojIyBURiByYW5raW5nIHBsb3QKVEYgcmFua2luZyBwbG90IHNob3dzIHN0YXRpc3RpYyAkLWxvZ197MTB9KFAgdmFsdWUpJCBhc3Nlc3NpbmcgdGhlIGFudGktY29ycmVsYXRpb24gbGV2ZWwgCm9mIFRGcyBleHByZXNzaW9uIGxldmVsIHdpdGggYXZlcmFnZSBETkEgbWV0aHlsYXRpb24gbGV2ZWwgYXQgc2l0ZXMgd2l0aCBhIGdpdmVuIG1vdGlmLiAKQnkgZGVmYXVsdCwgdGhlIHRvcCAzIGFzc29jaWF0ZWQgVEZzIGFuZCB0aGUgVEYgZmFtaWx5IG1lbWJlcnMgKGRvdHMgaW4gcmVkKSB0aGF0IGFyZSBhc3NvY2lhdGVkIHdpdGggdGhhdCBzcGVjaWZpYyBtb3RpZiAgYXJlIGxhYmVsZWQgaW4gdGhlIHBsb3QuCkJ1dCB0aGVyZSBpcyBhbHNvIGEgb3B0aW9uIHNob3cgaGlnaGxpZ2h0IG9ubHkgVEYgc3ViLWZhbWlseSBtZW1iZXJzIChUQ0NsYXNzIGRhdGFiYXNlIGNsYXNzaWZpY2F0aW9uKQoKU2hvd24gYXJlIFRGIHJhbmtpbmcgcGxvdHMgYmFzZWQgb24gdGhlIHNjb3JlICgkLWxvZ197MTB9KFAgdmFsdWUpKSQgb2YgYXNzb2NpYXRpb24gYmV0d2VlbiBURiBleHByZXNzaW9uIGFuZCBETkEgbWV0aHlsYXRpb24gb2YgdGhlIFA3MyBtb3RpZiBpbiB0aGUgTFVTQyBjYW5jZXIgdHlwZS4gVGhlIGRhc2hlZCBsaW5lIGluZGljYXRlcyB0aGUgYm91bmRhcnkgb2YgdGhlIHRvcCA1JSBhc3NvY2lhdGlvbiBzY29yZS4gVGhlIHRvcCAzIGFzc29jaWF0ZWQgVEZzIGFuZCB0aGUgVEYgZmFtaWx5IG1lbWJlcnM9KGRvdHMgaW4gcmVkKSB0aGF0IGFyZSBhc3NvY2lhdGVkIHdpdGggdGhhdCBzcGVjaWZpYyBtb3RpZiBhcmUgbGFiZWxlZCBpbiB0aGUgcGxvdAoKYGBge3IsZXZhbD1UUlVFLGZpZy5jYXA9IlNob3duIGFyZSBURiByYW5raW5nIHBsb3RzIGJhc2VkIG9uIHRoZSBzY29yZSAoLWxvZyhQIHZhbHVlKSkgb2YgYXNzb2NpYXRpb24gYmV0d2VlbiBURiBleHByZXNzaW9uIGFuZCBETkEgbWV0aHlsYXRpb24gb2YgdGhlIFA3MyBtb3RpZiBpbiB0aGUgTFVTQyBjYW5jZXIgdHlwZS4gVGhlIGRhc2hlZCBsaW5lIGluZGljYXRlcyB0aGUgYm91bmRhcnkgb2YgdGhlIHRvcCA1JSBhc3NvY2lhdGlvbiBzY29yZS4gVGhlIHRvcCAzIGFzc29jaWF0ZWQgVEZzIGFuZCB0aGUgVEYgZmFtaWx5IG1lbWJlcnM9KGRvdHMgaW4gcmVkKSB0aGF0IGFyZSBhc3NvY2lhdGVkIHdpdGggdGhhdCBzcGVjaWZpYyBtb3RpZiBhcmUgbGFiZWxlZCBpbiB0aGUgcGxvdCJ9CmxvYWQoInJlc3VsdC9nZXRURi5oeXBvLlRGcy53aXRoLm1vdGlmLnB2YWx1ZS5yZGEiKQptb3RpZiA8LSAiUDczX0hVTUFOLkgxME1PLkEiClRGLnJhbmsucGxvdChtb3RpZi5wdmFsdWUgPSBURi5tZXRoLmNvciwgCiAgICAgICAgICAgICBtb3RpZiA9IG1vdGlmLAogICAgICAgICAgICAgc2F2ZSA9IEZBTFNFKSAKYGBgCgoKU2hvd24gYXJlIFRGIHJhbmtpbmcgcGxvdHMgYmFzZWQgb24gdGhlIHNjb3JlICgkLWxvZ197MTB9KFAgdmFsdWUpJCkgb2YgYXNzb2NpYXRpb24gYmV0d2VlbiBURiBleHByZXNzaW9uIGFuZCBETkEgbWV0aHlsYXRpb24gb2YgdGhlIFA3MyBtb3RpZiBpbiB0aGUgTFVTQyBjYW5jZXIgdHlwZS4gVGhlIGRhc2hlZCBsaW5lIGluZGljYXRlcyB0aGUgYm91bmRhcnkgb2YgdGhlIHRvcCA1JSBhc3NvY2lhdGlvbiBzY29yZS4gVGhlIHRvcCAzIGFzc29jaWF0ZWQgVEZzIGFuZCB0aGUgVEYgc3ViLWZhbWlseSBtZW1iZXJzPShkb3RzIGluIHJlZCkgdGhhdCBhcmUgYXNzb2NpYXRlZCB3aXRoIHRoYXQgc3BlY2lmaWMgbW90aWYgYXJlIGxhYmVsZWQgaW4gdGhlIHBsb3QuCgpgYGB7cixldmFsPVRSVUUsZmlnLmNhcD0iU2hvd24gYXJlIFRGIHJhbmtpbmcgcGxvdHMgYmFzZWQgb24gdGhlIHNjb3JlICgtbG9nKFAgdmFsdWUpKSBvZiBhc3NvY2lhdGlvbiBiZXR3ZWVuIFRGIGV4cHJlc3Npb24gYW5kIEROQSBtZXRoeWxhdGlvbiBvZiB0aGUgUDczIG1vdGlmIGluIHRoZSBMVVNDIGNhbmNlciB0eXBlLiBUaGUgZGFzaGVkIGxpbmUgaW5kaWNhdGVzIHRoZSBib3VuZGFyeSBvZiB0aGUgdG9wIDUlIGFzc29jaWF0aW9uIHNjb3JlLiBUaGUgdG9wIDMgYXNzb2NpYXRlZCBURnMgYW5kIHRoZSBURiBzdWItZmFtaWx5IG1lbWJlcnM9KGRvdHMgaW4gcmVkKSB0aGF0IGFyZSBhc3NvY2lhdGVkIHdpdGggdGhhdCBzcGVjaWZpYyBtb3RpZiBhcmUgbGFiZWxlZCBpbiB0aGUgcGxvdCJ9CmxvYWQoInJlc3VsdC9nZXRURi5oeXBvLlRGcy53aXRoLm1vdGlmLnB2YWx1ZS5yZGEiKQptb3RpZiA8LSAiUDczX0hVTUFOLkgxME1PLkEiClRGLnJhbmsucGxvdChtb3RpZi5wdmFsdWUgPSBURi5tZXRoLmNvciwgIAogICAgICAgICAgICBtb3RpZiA9IG1vdGlmLCAKICAgICAgICAgICAgVEYubGFiZWwgPSBjcmVhdGVNb3RpZlJlbGV2YW50VGZzKCJzdWJmYW1pbHkiKVttb3RpZl0sCiAgICAgICAgICAgIHNhdmUgPSBGQUxTRSkKYGBgCgojIFNlc3Npb24gSW5mb3JtYXRpb24KCioqKioqKgpgYGB7ciBzZXNzaW9uSW5mb30Kc2Vzc2lvbkluZm8oKQpgYGAKCiMgUmVmZXJlbmNlcwo=